1 2 Previous Next 40 Replies Latest reply on Aug 24, 2016 7:42 AM by Trevorׅ

# What is the direction of the curve points returned by entirePath()? [See description for details]

The entirePath() of a polygon returned these points. As clarified in a different thread, we have established that the order is leftControlPoint anchorPoint rightControlPoint if there are control points at all. Otherwise it is just the anchor point.

The question I have here is, consider line 3, the control points specified there, do they represent the control points for the Bezier curve between Line 2 point and Line 3 point or a Bezier curve between Line 3 point and Line 4 point?

Thanks!

• ###### 1. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

I would think that the left control points go to the left (750,1234) which in your specific case is between 2 and 3 and that the right control points go to the right (757, 1238) which in your case is between 3 and 4.

• ###### 2. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

But I believe this is a quadratic Bezier curve and there need to be two control points to represent it accurately. How would that be satisfied if what you propose is true?

• ###### 3. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

I think it's cubic and not quadratic, I once looked into it and seem to remember that's what I found documented.

Time for some googling

• ###### 4. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

It's clearer if you present the path as an array of arrays (values rounded here):

[

[519,1135],

[613,1135],

[[647,1169],[750,1234],[757,1238]],

[782,1254],

[1536,2048]

]

The third line indicates that the anchor point is at [750,1234] and that the anchor has two handles. When you select an anchor with the direct selection tool you see any handles. The anchor point in line 3 has two handles: the incoming one ('leftDirection') is [647,1169], the outgoing one ('rightDirection') is [757, 1238]. The values are the coordinates of the handles. When you select a handle, the Transform panel shows the coordinates of the anchor, not the handle. (Only when you press a handle and you keep the mouse button down do you see the handle's coordinates, but very briefly.) But you can see a handle's coordinates in the Info panel, see the screenshot.

The selected anchor is at 186,400, the outgoing ('rightDirection') handle is at 220,400 (couldn't get the mouse pointer exactly on the spot). The path of this curve can be represented in several ways:

[

[[134, 500], [134, 457], [134, 420]],

[[150, 400], [186, 400], [220, 400]],

[[230, 420], [230, 436], [230, 457]],

]

or

[

[leftDirection = [134, 500],

anchor = [134, 457],

rightDirection = [134, 420]

],

[leftDirection = [150, 400],

anchor = [186, 400],

rightDirection = [220, 400]

],

[leftDirection = [230, 420],

anchor = [230, 436],

rightDirection = [230, 457]

],

];

Peter

• ###### 5. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

InDesign's curves and handles essentially work the same way as in FontLab, Fontographer, Illustrator, CorelDraw, etc.

P.

• ###### 6. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Thanks a ton for this comprehensive explanation!

• ###### 7. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

I have one more question. So I understand, the Bezier between two anchor points a and b can be drawn using the leftControl of b and rightControl of a. But according to the screenshot I posted above, it is not possible as there is no other anchor point with controlPoints so how would I draw a Bezier then?

• ###### 8. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Let's sort out some terminology: a Bézier curve is the whole curve. What you call 'control points' are usually called 'handles'. Those handles are used to change the shape of the curve. How exactly the shape is changed when you drag a handle depends on the type of anchor: smooth, symmetrical, etc.

If you have two anchors a and b, the shape of the curve connection a and b can be changed by dragging the outgoing handle of a and/or the incoming handle of b (assuming that you started at a).

To place an anchor with handles, choose the pen tool, click somewhere, keep the mouse button down, and drag somewhere. You'll see the handles appear. If you've not worked with Bézier before it can be a bit of a challenge but it's not really very difficult. Some practice will make things clear. Look into point conversion (Object > Convert point) and the Convert Direction Tool in the Tools menu. Doodle around and draw and change lots of curves!

P.

• ###### 9. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

I thought that every anchor point was connected by Bezier curves and using the control points I could draw a curve in HTML too. What do I do if I wish to do that?

• ###### 10. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

> I thought that every anchor point was connected by Bezier curves . . .

> . . . and using the control points I could draw a curve in HTML too. What do I do if I wish to do that?

In HTML? I haven't a clue.

• ###### 11. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

So to draw a Bezier curve between two points we need the two points between which we wish to draw a curve and two control points. So considering I have the information supplied by InDesign, how would that translate into the the format I require, that is basically my query.

• ###### 12. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Not so much an indesign question but you can mess around with HTML canvas bezierCurveTo() Method and google bezier curve html5 demo

• ###### 13. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

The below is pasted from there

#### Cubic Bezier curves

This example draws a heart using cubic Bézier curves.

function draw() {

var canvas = document.getElementById('canvas');

if (canvas.getContext){

var ctx = canvas.getContext('2d');

var path = new Path2D();

path.moveTo(75,40);

path.bezierCurveTo(75,37,70,25,50,25);

path.bezierCurveTo(20,25,20,62.5,20,62.5);

path.bezierCurveTo(20,80,40,102,75,120);

path.bezierCurveTo(110,102,130,80,130,62.5);

path.bezierCurveTo(130,62.5,130,25,100,25);

path.bezierCurveTo(85,25,75,37,75,40);

ctx.fill(path);

}

}

• ###### 14. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

So in the earlier example, this shape:

ctx.moveTo(20,20);

ctx.bezierCurveTo(20,100,200,100,200,20);

corresponds with the shape you get in InDesign with this script:

g.paths[0].entirePath =

[

[[20, 20], [20, 20], [20, 100]],

[[200, 100], [200, 20], [200, 20]],

];

The curve has two anchors. First anchor at 20,20; no handle, i.e. the incoming handle is on the anchor. The second point has no outgoing handle.

To translate InDesign's path to HTML, do a moveTo to the path's first anchor (myCurve.paths[0].pathPoints[0].anchor).

From there you can work out how to proceed.

P.

• ###### 15. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi all,

First, InDesign uses cubic Bezier curves.

And now, here is the best reference ever about dealing with Bezier curves:

A Primer on Bézier Curves

@+,

Marc

• ###### 16. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Marc Autret wrote:

And now, here is the best reference ever about dealing with Bezier curves:

A Primer on Bézier Curves

Wow! Now that is comprehensive!

I've bookmarked that page to read when I have the mental capacity to digest some of it...

Thanks!

Harbs

• ###### 17. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

The easiest way to draw this stuff in HTML is using EaselJS.

• ###### 18. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

HI Marc and all,

I made a script earlier in the year and read at least some that link then, it was a bit difficult to apply in practice in Illustrator or InDesign.

I needed to as per UI entry draw templates with arches at their ends using bezier curves.  For the simple 1/4 circles rounded corners I used an approximation of something like .55 for the right handle and .45 for the left.

Below is a snippet of part of the script (it was for Illustrator but the principles are the same for ID)

```const kLeft = r * 0.44771575927734444444, // constant for leftDirection handle for a 90 degree arc
kRight = r * 0.55228508843315972222; // constant for rightDirection handle for a 90 degree arc
var c, l, arcPaths, pathPoints;

top = (top == true || top == "top") ? "top" : "bottom";

arcPaths = {
top : { // top path starting from top right
anchors: [[x, y], [x - r, y - r]],
rightDirections: [[x, y], [x - r, y - kLeft]],
leftDirections: [[x - kRight, y], [x - r, y - r]],
pointTypes: [PointType.CORNER, PointType.CORNER]
},

bottom: { // bottom path starting from top left
anchors: [[x, y], [x + r, y - r]],
rightDirections: [[x, y], [x + kLeft, y - r]],
leftDirections: [[x, y - kRight], [x + r, y - r]],
pointTypes: [PointType.CORNER, PointType.CORNER]
}
};
```

The above would produce the paths and handles which I pushed into arrays to produce the shapes.

That was the easy bit.  The harder bit was that I needed to adds arches of a given radius and width / sagitta.

I wanted to do it mathematically but in the end took the path that I think the OP is taking of using ID or Ai as a crutch to do the math, so I got Ai to draw a circle and a correctly placed rectangle, excluded the rectangle from the circle copied the path of the resulting arc, removed the arc and added the path to the shapes entire path array.

To draw a circle one would use 4 1/4 circles that would be easy enough, to draw an ellipse presumably one would average out the handles in some form of proportion to the translation or the ellipses anchor points from the circle anchor points.  I haven't experimented to get it to work.

What I wanted to do was to make a generic function for segments of ellipses, of height h and width w starting from and a and ending at b.

I know from you sin script tat you read up on the topic. Do you know how to go about it?

Regards

Trevor

• ###### 19. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi Trevor,

I didn't work specifically on ellipses (so far) but I suppose all could be done by just scaling data from basic circle path points. So the main question is about managing circles (and circle arcs) in terms of cubic Bezier curves.

As we already know a Bezier curve cannot perfectly match an exact circle but there are decent approximations (InDesign native circle routine is not very good, by the way). A good read on this issue is: Approximate a circle with cubic Bézier curves (There are also technical details in Drawing Sine Waves in InDesign, although this is a subsidiary topic.)

There are great libraries to study Bezier art in depth. For JavaScript dev I specially recommand Paper.js (many interesting snippets here). And at a higher level (C++) we have of course Inkscape's source code: https://inkscape.org/en/download/source/

Using DOM commands (Pathfinder operations etc.) remains the easier solution anyway… as long as you do not question performances.

Now, going back to your question, give us more detail on what your routine is exactly supposed to do in terms of input/output, then maybe I could bring a starting point.

@+

Marc

• ###### 20. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

pkahrel wrote:

InDesign's curves and handles essentially work the same way as in FontLab, Fontographer, Illustrator, CorelDraw, etc.

.. and inside Type 1 PostScript fonts! (But not TTF fonts. Now those are quadratic, not cubic.)

• ###### 21. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Trevor, there is a very nice PDF floating around on the web which explains in detail the differences between bezier curves and circle segments. But (looking at your magic values) perhaps you've already seen it?

(As a note to others: mathematically you can prove that you cannot draw circles - or ellipses - using bezier curves only, although you can approximate them. Technically, neither InDesign's nor Illustrator's circles are, in fact, actual circles.)

• ###### 22. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi Marc and Jongware

I'll get back tomorrow afternoon.

Trevor

• ###### 23. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

This is exactly what I wanted! Thanks a lot!

Rishabh K

• ###### 24. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Ok, the afternoon came and went.

I did see a lot of sources on the topic but didn't understand how to apply the theory and the terms used in them to practical ID, AI scripting terms.

I am using the terms circles, ellipses etc. as what the look like and what most "normal" people would call them even though I fully understand that they are approximations.  I did see in one of the sources (no idea which) that a better value can be given instead of the standard .552... that is used.  The numbers that I used I think I got by looking at the paths that Ai was producing.  The numbers didn't produce a fixed constant a bigger "circle" produced a different number than a smaller one.

I only noticed now that I didn't need to use 2 numbers .522... and .447... as the .447... is 1 - .52222

I looked today at the Paper.js in particular the function that starts at line 4474 of the paper-core.js file.  Which I shall paste below.

It helps a very lot in understanding things.  Now that from this post we know the conversion from extended script to and from the html "ctx.bezierCurveTo()" it opens up the topic tremendously.

```_draw: function(ctx, param, strokeMatrix) {
var style = this._style,
hasFill = style.hasFill(),
hasStroke = style.hasStroke(),
dontPaint = param.dontFinish || param.clip,
untransformed = !strokeMatrix;
if (hasFill || hasStroke || dontPaint) {
var type = this._type,
isCircle = type === 'circle';
if (!param.dontStart)
ctx.beginPath();
if (untransformed && isCircle) {
ctx.arc(0, 0, radius, 0, Math.PI * 2, true);
} else {
size = this._size,
width = size.width,
height = size.height;
if (untransformed && type === 'rectangle' && rx === 0 && ry === 0) {
ctx.rect(-width / 2, -height / 2, width, height);
} else {
var x = width / 2,
y = height / 2,
kappa = 1 - 0.5522847498307936,
cx = rx * kappa,
cy = ry * kappa,
c = [
-x, -y + ry,
-x, -y + cy,
-x + cx, -y,
-x + rx, -y,
x - rx, -y,
x - cx, -y,
x, -y + cy,
x, -y + ry,
x, y - ry,
x, y - cy,
x - cx, y,
x - rx, y,
-x + rx, y,
-x + cx, y,
-x, y - cy,
-x, y - ry
];
if (strokeMatrix)
strokeMatrix.transform(c, c, 32);
ctx.moveTo(c[0], c[1]);
ctx.bezierCurveTo(c[2], c[3], c[4], c[5], c[6], c[7]);
if (x !== rx)
ctx.lineTo(c[8], c[9]);
ctx.bezierCurveTo(c[10], c[11], c[12], c[13], c[14], c[15]);
if (y !== ry)
ctx.lineTo(c[16], c[17]);
ctx.bezierCurveTo(c[18], c[19], c[20], c[21], c[22], c[23]);
if (x !== rx)
ctx.lineTo(c[24], c[25]);
ctx.bezierCurveTo(c[26], c[27], c[28], c[29], c[30], c[31]);
}
}
ctx.closePath();
}
```

From this it should be pretty simple to parse in the jsx.  With this we can draw an ellipse, or a 1/4, 1/2 and 3/4 ellipse using 1, 2, 3 or 4 bezier curves.

This is really all I need, but what I would like is to be able to start and end at any point in the ellipse.

Given H, W, and start and end angles S and E how would I calculate the black bezier curve on the right side of the screenshot?

• ###### 25. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Okay Trevor let's go into this!

I won't use Paper.js in my example as I have already coded a similar routine in a work-in-progress—Claquos v3—so I'll be more comfortable with my personal code.

My basic idea is, don't work with an ellipse when you can just rescale a circle (through a transformation matrix, etc.) So I'll start with a circular arc.

My main reference when I was implementing the below routine was Circular Arcs and Circles. You find there a clear explanation and method for computing the right Bézier weight for a specific arc in [0,pi/2]. Then, all we need to do is to create as many control points as needed to cover arcs over 90 degree. Here my approach is to divide the entire arc in equal sub-arcs so that I just have to deal with a single Bézier weight calculation and then apply a rotation to the successive control points. (Also, we want to manage a global rotation angle to support your S parameter, but it's not a big deal.)

```// ---
// This is part of my Claquos v3 script (not released yet.)
// ---
\$.hasOwnProperty('Arc')||(function(H/*OST*/,S/*ELF*/,I/*NNER*/)
{
H[S] = S;

I.F_ROTATOR = function F(/*num[2][]&*/a)
// -------------------------------------
// A rotation utility.
{
if( !a )
{
F.FACTOR = 1e3;
F.COS = 1;
F.SIN = 0;
{
F.COS = Math.cos(a);
F.SIN = Math.sin(a);
});
return F;
}

var cos = F.COS,
sin = F.SIN,
factor = F.FACTOR,
x, y,
i = a.length;

while( i-- )
{
x = a[i][0];
y = a[i][1];

a[i][0] = (x*cos + y*sin)/factor;
a[i][1] = (y*cos - x*sin)/factor;
}
};

// -------------------------------------
// Get the perfect Bezier weight for that angle.
{
var a = ANGLE_IN_RADIANS ? angle : ((angle * Math.PI) / 180),

return ( 4 * (Math.sqrt(radius*radius - 2*x) - (x-1)) ) / ( 3*y );
}

// -------------------------------------
// Generate the entire path.
{
var FX = I.F_ROTATOR(),
// ---
n = 2 + (arcDeg>90) + (arcDeg>180) + (arcDeg>210),
// ---
kAlpha = r * I.F_TANGENT_FACTOR(r, alphaDeg/2),
// ---
path, i, z, t;

FX.rotate(rotDeg);

for( path=[], i=z=0 ; i <= n ; ++i )
{
t = path[z++] = [ null, [r,0], null ];
t[0] = i > 0 ? [r, kAlpha] : t[1].concat();
t[2] = i < n ? [r, -kAlpha] : t[1].concat();
FX(t);
}

return path;
};

// -------------------------------------
// API
// -------------------------------------

S.buildPath = I.F_ARC_PATH;

})(\$,{toString:function(){return 'Arc'}},{});

// ---
// TEST -- assuming the ruler space is OK, in pt, etc.
// ---

strokeColor:'Black',
fillColor:'None',
strokeWeight:'3pt'
}).paths[0].properties = {
entirePath: path,
pathType:   +PathType.OPEN_PATH,
};
```

From then the only question you have to deal with is to find the parameters (i.e. radius, rotation and arc angles) that fit your final ellipse, considering some scaling factor. I guess that will be the easy part ;-)

Of course I strongly suggest that you implement the scaling transformation at the path computation level (rather than scaling the circle after its creation) since every DOM command has a cost. But you already knew that.

Hope that helps.

@+,

Marc

• ###### 26. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Very Nice Marc!

From then the only question you have to deal with is to find the parameters (i.e. radius, rotation and arc angles) that fit your final ellipse, considering some scaling factor. I guess that will be the easy part ;-)

My only doubt is just how easy the "easy part" will be.

I shall give it a go.

Thanks hope the help and time you put into it,

Trevor

• ###### 27. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi Trevor,

My only doubt is just how easy the "easy part" will be.

Sorry but we'll need a little bit of math here. Take R = W / 2 and k = W / H.

k is the y-scaling factor that sends the ellipse to the circle (and inversely 1/k is the y-scaling factor we shall apply to the circular arc.)

Since your parameters provide the start and end angles relative to the ellipse, the problem is to determine the corresponding angles in the circular area (that is, before stretching the circle).

Given an angle α relative to the ellipse, what is the corresponding angle α' relative to the circle? Let's solve this first in the usual trigonometric form:

Now we can write an adapter to convert ellipse parameters into circle parameters. The code below also takes care of the angular reference frame you used in your example.

```// Original Trevor's parameters
// ---
var W = 400,
H = 144,
S = 57,  // in degree, origin +90, reversed
E = 212; // in degree, origin +90, reversed

// ---
k = W/H,
convertEllipseToCircleAngle = function(a)
{
},
// ---
start = convertEllipseToCircleAngle(90-E),
end = convertEllipseToCircleAngle(90-S),
arc = end-start;
while( arc <= 0 ) arc+=360;

// Build the circular arc using \$.Arc (see previous post.)
// ---

strokeColor:'Black',
fillColor:'None',
strokeWeight:'2pt'
});
arc.paths[0].properties = {
entirePath: path,
pathType:   +PathType.OPEN_PATH,
};

// Y-rescale by 1/k (relative to the space origin.)
// [This should be done at the coordinate level for better performance!]
// ---
arc.resize(
[[0,0],AnchorPoint.centerAnchor], // this refers to the ruler origin
ResizeMethods.MULTIPLYING_CURRENT_DIMENSIONS_BY,
[1,1/k]
);
```

That's it! Here is how the script behaves for decreasing values of H:

Note that the resulting angles S and E remains constant, as expected

@+

Marc

• ###### 28. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

These are works of art. . .

• ###### 29. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Excellent Marc!

Better still is.

```// Original Trevor's parameters
// ---
var W = 400,
H = 144,
S = 57,  // in degree, origin +90, reversed
E = 212; // in degree, origin +90, reversed

// ---
k = W/H,
convertEllipseToCircleAngle = function(a)
{
},
// ---
start = convertEllipseToCircleAngle(90-E),
end = convertEllipseToCircleAngle(90-S),
arc = end-start;
while( arc <= 0 ) arc+=360;

// Build the circular arc using \$.Arc (see previous post.)
// ---

// Y-rescale by 1/k (relative to the space origin.)
// ---
var l = path.length,
p, ll, n, c;

for (n = 0; n < l; n++) { // loop through the circle segments
p = path[n]
ll =p.length;
for (c = 0; c < ll; c++) { // loop through Anchor, left and right points
p[c][1] /= k; // fix up the vertical scales
}
}

strokeColor:'Black',
fillColor:'None',
strokeWeight:'2pt'
});
arc.paths[0].properties = {
entirePath: path,
pathType:   +PathType.OPEN_PATH,
};
```

This way we avoid using the DOM resize call.  This is what I need to get all the points with no DOM calls and just at the end to make the one DOM call.

The idea is to make an API to easily draw shapes in the following sort of form.

```// Very Very rough numbers to make the magenta colored inner shape of the screen shot
// Aimed for Api
var path = new Shape(); // Shape is the path factory

path.start(40,500); // starting point of path
path.right(300); // or path.east (300)
path.down(300); // or path.right(300) or path.south(300)
// continue the path at a 46 degree angle for 60 points
path.right(46, 60);
// continue with an arc of radius 1000 (for ellipse could use [1000, 700] starting from 230 degrees going to 290 degrees
path.arc(500, 230, 290);
// continue the end of the arc at the current angle of the end of the arc i.e. the tangent angle of 290 by 60 points
path.continue(60);
path.up(300);
path.draw({strokeColor: 'Magenta', strokeWeight: '3pt'}); // will draw the shape with properties
```
```
```

The last stage of the arc function would be to allow for a rotation of the arc around the starting point.

That should be pretty basic trigonometry, I shall give it a go and hopefully post it on Sunday. (you can post it sooner if you like!)

Thanks for all you help, I'm sure this will be very useful particularly for Illustrator scripters  who are doing more drawing stuff.

Regards

Trevor

• ###### 30. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

This would go after the resize part.

```// Rotate Arc from the start point by r degrees
// --
var R = 35, // Trevor's random rotation angle;
h = path[0][0][0], // horizontal start point
v = path[0][0][1]; // vertical start point
for (n = 0; n < l; n++) { // loop through the circle segments
p = path[n]
ll =p.length;
for (c = 0; c < ll; c++) { // loop through Anchor, left and right points
Rotate(p[c], [h,v], R);
}
}

function Rotate(point, origin, r) {
var x = point[0],
y = point[1],
ox = origin[0],
oy = origin[1];

point[0] = (x - ox) * Math.cos(r) - (y - oy) * Math.sin(r) + ox,
point[1] = (x - ox) * Math.sin(r) + (y - oy) * Math.cos(r) + oy;
}
```
• ###### 31. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi All,

I think Jive's went a bit berserk and posted part of an earlier post of mine by itself, anyway I did not post it, and now I deleted it.

I did try to post another post which Jive's deleted. So here's the summary, this time typed on a text editor so it doesn't get trashed so easily.

In short; Marc has done an absolutely brilliant job in illustrating how to apply the Bezier mathematics in a practical way in InDesign and the like that makes it now easier to draw complex arcs using his functions than using the traditional path finder DOM methods. To convert the output to HTML has been illustrated in the early part of the thread opening all sorts of possibilities including producing live previews on HTML based extensions.

I have changed the structure of the functions to make it more simple for us mortals who are not yet familiar with hi unpublished Claquos v3.

I added a few functions including the ability to choose which end of the arc it the beginning.

The Screenshot below is the result of the below script.

Thanks Marc!

Regards,

Trevor.

```// Taken from Marc https://forums.adobe.com/message/8072664#8072664

var ArcPath, F_ROTATOR, F_TANGENT_FACTOR, EllipseArc;
var ArcPath = function(/*]0...[*/ radius,/*]0,360]*/ arcDeg ,/*[0,360[*/ rotDeg, reversePath /*[Bool]*/)
// By Marc Autret
// -------------------------------------
// Generate the entire path.
{
var FX = F_ROTATOR(),
// ---
n = 2 + (arcDeg>90) + (arcDeg>180) + (arcDeg>210),
// ---
kAlpha = r * F_TANGENT_FACTOR(r, alphaDeg/2),
// ---
path, i, z, t;

FX.rotate(rotDeg);
if (!reversePath) {
for( path=[], i=z=0 ; i <= n ; ++i ) {
t = path[z++] = [ null, [r,0], null ];
t[0] = i > 0 ? [r, kAlpha] : t[1].concat();
t[2] = i < n ? [r, -kAlpha] : t[1].concat();
FX(t);
}
} else { // this will make path[0][0] at the "other" end of the arc
// else part by Trevor
path=[];
i=z=n+1;
while (i--) {
t = path[--z] = [ null, [r,0], null ];
t[0] = i > 0 ? [r, -kAlpha] : t[1].concat();
t[2] = i < n ? [r, kAlpha] : t[1].concat();
FX(t);
} ;
}
return path;
};

F_ROTATOR = function F(/*num[2][]&*/ a)
// By Marc Autret
// -------------------------------------
// A rotation utility.
{
if( !a )
{
F.FACTOR = 1e3;
F.COS = 1;
F.SIN = 0;
{
F.COS = Math.cos(a);
F.SIN = Math.sin(a);
});
return F;
}

var cos = F.COS,
sin = F.SIN,
factor = F.FACTOR,
x, y,
i = a.length;

while( i-- )
{
x = a[i][0];
y = a[i][1];

a[i][0] = (x*cos + y*sin)/factor;
a[i][1] = (y*cos - x*sin)/factor;
}
};

// By Marc Autret
// -------------------------------------
// Get the perfect Bezier weight for that angle.
{
var a = ANGLE_IN_RADIANS ? angle : ((angle * Math.PI) / 180),

return ( 4 * (Math.sqrt(radius*radius - 2*x) - (x-1)) ) / ( 3*y );
}

// This is the main function for drawing ellipse arcs
// ---
EllipseArc = function (W, H, S, E, R, reversePath /*[Bool]*/) { // Width, Height, Start and End in degrees, origin +90, reversed Rotation in Degrees
// By Marc Autret
k = W/H,
convertEllipseToCircleAngle = function(a)
{
},
// ---
start = convertEllipseToCircleAngle(90-E),
end = convertEllipseToCircleAngle(90-S),
arc = end-start;
while( arc <= 0 ) arc+=360;

var path = ArcPath(radius, arc, start, reversePath);
// Y-rescale by 1/k (relative to the space origin.)
// ---
var l = path.length,
p, ll, n, c;

for (n = 0; n < l; n++) { // loop through the circle segments
p = path[n]
ll =p.length;
for (c = 0; c < ll; c++) { // loop through Anchor, left and right points
p[c][1] /= k; // fix up the vertical scales
}
}

if (R) {
// Rotate Arc from the start point by r degrees
// --
Rotate(path, R);
}
return path;
}

Rotate = function (path /*object or array*/, R) { // Rotates all the points in the path around the starting point of the path
// By Trevor
R *= Math.PI / 180; // Convert to radians
var h = path[0][1][0], // horizontal start point
v = path[0][1][1], // vertical start point
n, p, l, ll, c;
l = path.length;
for (n = 0; n < l; n++) { // loop through the circle segments
p = path[n]
ll =p.length;
for (c = 0; c < ll; c++) { // loop through Anchor, left and right points
RotatePoint(p[c], [h,v], R);
}
}
}

RotatePoint = function (point /*[Array x,y]*/, origin /*[Array x,y]*/, r /*num degrees from +90*/) { // Rotates any given point around any other given point
// By Trevor
var x = point[0],
y = point[1],
ox = origin[0],
oy = origin[1];

point[0] = (x - ox) * Math.cos(r) - (y - oy) * Math.sin(r) + ox,
point[1] = (x - ox) * Math.sin(r) + (y - oy) * Math.cos(r) + oy;
}

MoveTo = function (path /*object or array*/, x, y) { // translates the path to start at a give point
// By Trevor
var q = path.length - 1;
var h = x - path[0][1][0], // horizontal translation from start point
v = y - path[0][1][1], // vertical translation from start point
n, p, l, ll, c;
ll = path.length;
for (n = 0; n < ll; n++) { // loop through the circle segments
p = path[n]
l =p.length;
for (c = 0; c < l; c++) { // loop through Anchor, left and right points
p[c][0] += h;
p[c][1] += v;
}
}
}

Scale = function (path, x, y /* number X scale i.e. 1.2 for 120% */) {
// By Trevor
var n, p, l, ll, c;
ll = path.length;
for (n = 0; n < ll; n++) { // loop through the circle segments
p = path[n]
l =p.length;
for (c = 0; c < l; c++) { // loop through Anchor, left and right points
p[c][0] *= x;
p[c][1] *= y;
}
}
}

// ---
// TEST
// ---

function drawSomething () {
// By Trevor
var n, path, c,
viewPreferences: {horizontalMeasurementUnits: 'pt', verticalMeasurementUnits: 'pt'},
documentPreferences: {pagesPerDocument: 1, pageHeight: '1900pt', pageWidth: '1150pt'}
});
cmyk = ['Cyan', 'Yellow', 'Magenta', 'Black'];

for (c = 0; c < 2; c++) {
path = EllipseArc(200, 70, 100, 300, 10, c % 2 /* Boolean to reverse starting point of path */);
for (n = 0; n < 360; n++) { // change to 15 to get a better idea of what the path reversing does
// Face and Trunk
Scale(path, .99, .99);
Rotate(path, n * 2);
MoveTo (path, 200 + .5 * n, 150 + ((c) * 300) + 40 * Math.cos (n * 2 * DEG2RAD));
strokeColor: cmyk[n % 4],
fillColor: cmyk[(n + 1) % 4],
fillColor: cmyk[(n + 1) % 4],
strokeWeight:'.5pt',
name: "shape"
}).paths[0].properties = {
entirePath: path,
pathType:   +PathType.CLOSED_PATH,
};
}
}
}

app.doScript (drawSomething, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.FAST_ENTIRE_SCRIPT);

```
• ###### 32. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi Marc

I am doing some work on this now and was wondering why you have a factor F.FACTOR = 1e3 and why you set it to 1000?

You are multiplying the radius by the factor and then you divide by the factor so any non 0 number will produce the same result.

If it wasn't you I wouldn't ask the question but as it is you I'm sure you have good reason!

Regards

Trevor

• ###### 33. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi Trevor,

Good question. My answer will be disappointing, I'm afraid. My original purpose was all about increasing the precision of the final coordinates, considering the fact that IEEE754 arithmetic (floating-point numbers) is an approximation of real number arithmetic, especially when additive operations are involved. My reasoning was as follows: we know IEEE754 is just a finite set of numbers (an infinite set of real numbers can't be described with that system). Then I was supposing that adding/subtracting high numbers rather than small numbers was a way of reducing rounding errors, because if the error density is the same at any scale then finally dividing by some factor will perhaps reduce the rounding error by that factor. But to be honest there are many points in my reasoning which I'm not sure at all. I made assumptions about error density which in fact I can't prove based on the mantissa|exponent representation of floating-point numbers. Also, I'm not sure that multiplying (first) and dividing (last) does not introduce errors of the same amount that those I want to reduce (however, it is known that IEEE754 multiplication is safer than addition, so…) Finally, that 1e3 factor is purely empiric and arbitrary. Maybe a 2^n factor would be much more convenient. Etc.

Reconsidering my code after several months, I don't feel it that good and exemplary. The logic is OK but the implementation is highly questionable, indeed.

@+

Marc

• ###### 34. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi Marc,

I think in truth that the even if one could get perfect coordinates the accuracy margin would be at a guess a 0.0000001 difference at most, this difference in our case is going to be irreverent as a 'perfect' bezier circle has an inaccuracy of about .02% of a true perfect circle at the max deviating points. So whether the accuracy is .02% or .0200001% is not important. In any case we'll never be able to see the difference even on the highest resolution printers.

The fact off the matter is that your code shows how to apply the bezier maths in a practical form and is a huge help to me.

I would like to improve on my implementation of the ellipse and rotation parts which I feel should be compressed into a single loop and not 1st draw a circle arc 2nd scale to ellipse and 3rd rotate to desired angle 4th translate the object to the desired coordinates.

Perhaps I am guilty of trying to make scripts that takes 2 seconds to execute take 1.999 seconds. Either way making the compressed form would be  an interesting mathematical challenge.

Regards and thanks again,

Trevor

• ###### 35. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

You are definitely not guilty, since scaling and translation calculations are easy to prepend. That will remove two DOM commands and undoubtedly speed up the script in a noticeable way. Especially if it has to generate a bunch of ellipses.

Have fun!

@+

Marc

• ###### 36. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

I think in the nearly a year since the scripts were posted you forgot that my version only calls the DOM command once after all the calculations have been made.

• ###### 37. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi colleagues,

this is a very interesting discussion.

Recently I did some studies on the precission that the Pathfinder tools are doing.
I found that e.g. Adobe Illustrator is more precise than InDesign and searching for a way to do more accurate operations with the Pathfinder tools. Maybe by scaling the objects first before applying a Pathfinder action. I don't know, if this is the right place to discuss this here or maybe it's better to open another thread.

I'm bussy right now, but can come back this evening with some samples, that show a few things.
Also related is the maximum zoom percentage one can zoom in and out with InDesign. Way better is the current Illustrator in this regards…

Uwe

• ###### 38. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

Hi Uwe,

1) Interesting, but the whole point of the exercise here is to not use any pathfinder tools. See 29 above.

2) The API I am working on is basically for Illustrator. (Actually a form of Illustrator server ) . As the API is so removed from DOM operations I would like it to work also on InDesign but it's a little bit complicated to cover them both as the vertical positions of the 2 applications are annoyingly opposite!

Regards

Trevor

• ###### 39. Re: What is the direction of the curve points returned by entirePath()? [See description for details]

I wonder if the precision  difference is because due to the bounding box that Illustrator draws is around the path points where as InDesign wraps the line thickness of the path in the bounding box?

1 2 Previous Next