Copy link to clipboard
Copied
Dear all,
After the first step (drawing a single line) I now try to draw a polyline. But i have no success:
I tried to interprete the the FDK reference and the Scripting Guide - but I fail to transfer these definitions to JS data types.
FDK reference
F_PointsT: describes a set of coordinate pairs. It is normally used to describe the vertices of a graphic object, such as a polyline or polygon.
typedef struct {
UIntT len; /* Number of coordinate pairs */
F_PointT *val; /* Vector of coordinate pairs */
} F_PointsT;
Dash: Data type Metrics. Specifies a dash pattern that is repeated for the length of an object's border. The
pattern is stored in a MetricsT structure. The 0th element of the MetricsT.MetricsT_val array stores the length of the first dash; the 1st element
stores the following space; the 2nd element stores the next dash; and so on for an even number of elements.
Metrics: Under this heading some functions to handle metrics are given, but no explanation. I do not find a useful definition.
MetricsT structure: defined as
typedef struct {
UIntT len; /* Number of metric values*/
MetricT *val; /* Array of metric values */
} F_MetricsT;
Scripting Guide
Points: An Array of Point objects with integer indexing and a length property.
Point: is described just as two integer values x and y.
Dash: Same text as in FDK
Metrics: An Array of objects with integer indexing and a length property. ➔ what kind of objects?
This is my script
#target framemaker
var oDoc = app.ActiveDoc, cm = 1857713;
Main(oDoc);
function Main(oDoc) {
var oFrame, oLine1, oPoly1;
if (!oDoc.ObjectValid()) {
alert ("A document must be active.");
return;
}
oFrame = oDoc.FirstSelectedGraphicInDoc;
if (!oFrame.ObjectValid()) {
alert ("An anchored frame must be selected.");
return;
}
oPoly1 = DrawPoly(oDoc, oFrame);
}
function DrawPoly(oDoc, oFrame) {
var j, jLast, k, oPoly = oDoc.NewPolyline(oFrame), oPoints = [4, 1, 6, 2, 8, 1, 10, 2];
jLast = oPoints.length-1; // last index
for (j = 0; j <= jLast; j++) { // convert into internal units
oPoints
= oPoints * cm; }
oPoly.PolyIsBezier = 0; // 0: unsmooth; 1: smooth ?
oPoly.BorderWidth = 0.05*cm; // Stroke-width
oPoly.LocX = oPoints[0]; // otherwise has
oPoly.LocY = oPoints[1]; // precedence over 1st point
oPoly.Points = oPoints;
oPoly.Width = oPoints[jLast-1] - oPoints[0]; // object dimensions
oPoly.Height= oPoints[jLast] - oPoints[1]; // default : 1/4"
oPoly.Fill = 15; // Pattern: 0: filled, 7: white, 15: clear
oPoly.Color = 0; // black?
oPoly.Dash = [cm, 0.5, 0.5, 0.2, 0.2]; // ?
return oPoly;
}
And this is the output
The red item is what I want to achieve and the black is what the script produces.
Copy link to clipboard
Copied
Even using the function Point (x,y) as described in the Scripting Guide (Function Summary), i have no success. The statement
oPoints = [Point(4*CM, 1*CM), Point(6*CM, 2*CM), Point(8*CM, 1*CM), Point(10*CM, 2*CM)];
yields message Point() is not a function!
var oPoints = [[4*CM, 1*CM], [6*CM, 2*CM], [8*CM, 1*CM], [10*CM, 2*CM]];
is accepted by ESTK, but creates only a line. The UI reports a PolyLine at 0/0 with width=height = 0.635 cm (1/4"). The Stroke width is as set in the script:
I have also found this:
var oPoints = [1, 1, 3, 2];seems to work - why then not in Polyline?
Where is a description of the required data types in JS terminology?
I'ts also an imposition that for every graphic object (line, arc, ellipse...) simply all properties for any object are listed (most likely by a text inset). IMHO it is at least misleading that a circle can have an arrow head. Well this is obvious, but others are not at all.
Maybe I need to bridle the tail of the ferd and look for a script which lists the set of properties of a selected object...
Copy link to clipboard
Copied
I have now selected my reddish polyline and run this simple script:
var oDoc = app.ActiveDoc;
var oObject = oDoc.FirstSelectedGraphicInDoc;
$.writeln (oObject.Points[0]);
But I get only this:
[object Point]
And the Data Browser is very closed about the Points:
So even inspecting existing objects does not reveal the nature of the point structure... GRRRRRRRRRRRRRR
How on earth can i find out how to define the points for the polyline?
Copy link to clipboard
Copied
Klaus,
The Data Browser does hide some useful information, but it can be made to reveal its secrets. In your case if you address the object's x or y properties like this you will get the result that may help:
$.writeln (oObject.Points[0].x);
$.writeln (oObject.Points[0].y);
I've not tried to create a polyline yet, but perhaps explicitly referencing x and y will do what you need?
Ian
Copy link to clipboard
Copied
Hi klaus,
creating a list of Points should work like this:
var point1 = new Point(1, 2);
var point2 = new Point(4, 5);
var points = new Points();
points.push(point1)
points.push(point2)
point1.x gives the x-coordinate of a point
point2.y gives the y-coordinate of a point
both values are changeable
Note: you need to provide metrics and not cm or Inches.
To convert cm 2 metric you can use this function
function convertCm2Metric(widthCm)
{
var cm2pt = 28.35;
return Math.round (widthCm * 65535 * cm2pt)
}
Hope this helps
Markus
Copy link to clipboard
Copied
@Ian: Thanks - this lets me see what I have at a selected polyline:
var j, oDoc = app.ActiveDoc, oObject, nPoints;
oObject = oDoc.FirstSelectedGraphicInDoc;
nPoints = oObject.NumPoints
for (j = 0; j < nPoints; j++) {
$.writeln (oObject.Points
.x, oObject.Points .y); }
With Markus' idea I could create the points (see script output), but the drawn graphic is by no means what I expect (reddish polyline) accoring to the Points.
#target framemaker
var oDoc = app.ActiveDoc, CM = 1857713; // Constants.FV_Metric_CM not present in ESTK
Main(oDoc);
function DrawPolyLine(oDoc, oFrame, rVertices, iSmooth) { // === Draw a polygon line ====
var j, jMax, minX, maxX, minY, maxY, oPoly = oDoc.NewPolyline(oFrame);
jMax = rVertices.length/2; // number of points
minX = minY = Number.MAX_VALUE;
maxX = maxY = 0; // in units
for (j = 0; j < jMax; j++) {
oPoint = new Point (rVertices[j*2]* CM, rVertices[j*2+1]* CM);// convert into internal units
$.writeln (oPoint.x + " " + oPoint.y);
oPoly.Points.push(oPoint);
if (rVertices[j*2] < minX) {minX = rVertices[j*2];}
if (rVertices[j*2+1] < minY) {minY = rVertices[j*2+1];}
if (rVertices[j*2] > maxX) {maxX = rVertices[j*2];}
if (rVertices[j*2+1] > maxY) {maxY = rVertices[j*2+1];}
}
oPoly.Fill = 15; // equiv Pattern: 0: filled, 7: white, 15: clear
oPoly.Color = 0; // black?
oPoly.BorderWidth = 0.05*CM; // Stroke-width
oPoly.Dash = [CM, 0.5, 0.5, 0.2, 0.2]; // not correct yet
oPoly.LocX = minX * CM;
oPoly.LocY = minY * CM;
oPoly.NumPoints = jMax;
oPoly.PolyIsBezier = iSmooth;
oPoly.Width = (maxX - minX) * CM; // object dimensions
oPoly.Height= (maxY - minY) * CM; // default : 1/4"
return oPoly;
} //--- end DrawPolyLine
function Main(oDoc) { // ==========================================================================
var oFrame, oLine1, oPoly1;
var rVertices = [4, 1, 3, 3, 8, 3, 6, 2]; // values in cm
if (!oDoc.ObjectValid()) {
alert ("A document must be active.");
return;
}
oFrame = oDoc.FirstSelectedGraphicInDoc;
if (!oFrame.ObjectValid()) {
alert ("An anchored frame must be selected.");
return;
}
if (oFrame.constructor.name === "AFrame") { // If it is an anchored frame, display its anchor type and width.
// alert ("Anchor type: " + oFrame.AnchorType + " width in CM: " + oFrame.Width/CM);
}
oPoly1 = DrawPolyLine(oDoc, oFrame, rVertices, 0); // unsmoothed line
} //--- end Main
Output:
7430852 1857713
5573139 5573139
14861704 5573139
11146278 3715426
Copy link to clipboard
Copied
Klaus,
drawing polylines is not easy with FrameMaker, as it depends on the order of points and also the settings of polyline properties also.
Fortunately I don't need to do this in my projects 🙂 but I did this in a very long time ago and remember the battle with FrameMaker.
What I would do is to draw a polyline that I expect, and check to points and the order they are set. After that, I would take exactly the same settings, and create the polyline by code with exactly the same values for each point shown in databrowser.
As soon as this works, I would add the same polyline with my own points. And as soon as this fits to, I would change polyline properties.
BTW:
oPoly.Color = 0; // black?
Color is an Object, and you have to get it from FM with doc.GetNamedColor("Black").
Please note Standard Color names are localized. You won't get "Black" in a German FM. You Need to call "Schwarz" or "Noir" for French FM.
and for this
oPoly.Fill = 15
I would use FM constans. Something like Constants.FV_FILL
Copy link to clipboard
Copied
Klaus,
I'm not sure if this would have any effect, but I wouldn't do that:
oPoly.Points.push(oPoint)
I would do
var points = new Points() ;
and assign all Points at once
oPoly.Points = points
In this case FM has nothing to draw while you are calculating the points
and perhaps I would set all oPoly props first and assign Points at last.
Copy link to clipboard
Copied
Hi Klaus,
I ran you code and digged a Little bit deeper into that.
As soon as you create a polyline (doc.NewPolyline) FM creates this Default 3 Point line.
Assigning NumPoints and Points later has no effect anymore.
This is why you get this Kind of line. Your Point calculation looks god.
So there must be another way to change the point settings of a polyline.
Perhaps I find some time this evening...
Markus
Copy link to clipboard
Copied
Klaus,
NumPoints and Points are readonly properties in ES (at least when I have a look to ObjectModel-Viewer)
So you can't change that properties directly.
But this also doesn't have any effect…
var existingPolypointsNum = oPoly.NumPoints;
for (var i=0; i < existingPolypointsNum; i++)
oPoly.Points.pop();
for (var i=0; i < points.length; i++)
oPoly.Points.push(points);
… but it should…
existing points are not removed and new points are not added.
and as it does not, I assume this feature seems not to be supported by ESTK... while it works with F_ApiSetPoints in FDK
Perhaps SetProps could help, but I don't think so.
For that reason I'm out. Perhaps someone else has an idea.
Markus
Copy link to clipboard
Copied
Hi Klaus and Markus,
I haven't posted much but I have been watching this thread and trying a bunch of code and I suspect that Markus is right: there is some kind of a flaw in the ExtendScript implementation. I tried SetProps as well and couldn't get it to work. If I get time, I will clean up my code and post it here and maybe you guys will get some ideas. But of course, if it is broken we might not be able to get it to work anyway.
Rick
Copy link to clipboard
Copied
@Markus:
«NumPoints and Points are readonly properties in ES (at least when I have a look to ObjectModel-Viewer)»
In FDK reference and FM-15 Scripting Guide it is just IntT - no mentioning of Read-Only. In the Object Reference (.chm) by Jongware (although for FM-12) it is defined readwrite. And in the Object Model Viewer I get:
Polyline.NumPoints ; Data Type: int ; Adobe FrameMaker-2017 Object Model
Where did you see the ReadOnly? Well, this does not prove that it is really writeable...
«What I would do is to draw a polyline that I expect, and check to points and the order they are set.»
The comparison of output and my 'reply' 5 shows that I already did that - because it is natural for math-affined people like me.
Yes, constants are good, if they exist. For the pen pattern only 3 of 15 are definable via constant. The metric values (e.g. FV_METRIC_CM) are not present in ESTK, justin FDK.
@Rick: It seems that PolyLine is broken in ESTK, because there is definitely no possibility to overcome the 3-point limit and the points are not set at all to the user values.
Even after halting the script after these statements Data Browser states: NumPoints = 3 and Points = [object Point],[object Point],[object Point]
var oPoly = oDoc.NewPolyline(oFrame);
oPoly.Points = [];
oPoly.Points.length = 0;
I will demomstrate this to Amitoj in Stuttgart.
Copy link to clipboard
Copied
Thought I could provide a Workaround by drawing single lines like this
for (j = 0; j < jMax -1; j++) {
var point1 = new Point (rVertices[j*2]* CM, rVertices[j*2+1]* CM);// convert into internal units
var point2 = new Point (rVertices[j*2 + 2]* CM, rVertices[j*2+3]* CM);// convert into internal units
var line = oDoc.NewLine(oFrame) ;
line.Points = new Points() ;
line.Points.push(point1) ;
line.Points.push(point2);
//$.writeln (oPoint.x + " " + oPoint.y);
//oPoly.Points.push(oPoint);
if (rVertices[j*2] < minX) {minX = rVertices[j*2];}
if (rVertices[j*2+1] < minY) {minY = rVertices[j*2+1];}
if (rVertices[j*2] > maxX) {maxX = rVertices[j*2];}
if (rVertices[j*2+1] > maxY) {maxY = rVertices[j*2+1];}
}
But there's the same issue. I think it's worth to create a Ticket for Adobe.
Read-Only:
If you press F1 in ESTK you get the Objectmodell-Viewer. If you open FM 2019 model and scroll to Polyline you see the property "Points". Its Icon is gray and in my interpreation this means "read-only".
In FDK this property is not read-only. So this is a gap/bug in ESTK and I think this issue is a general handling of Points-structure.
Hope this helps
Markus
Copy link to clipboard
Copied
Thanks, Markus, for this idea - but you can not create a smoot line this way...
For the sake of reference I have filed two bugs:
https://tracker.adobe.com/#/view/FRMAKER-5568 - ESTK Lack of implementation for various graphic objects
https://tracker.adobe.com/#/view/FRMAKER-5569 - ESTK Function PolyLine does not work at all
Both bug reports have an attached pdf with details.
The tough thing about these: this all is true since FM-10 (and for the Object Styles since FM-11).
I think, our ideas are exhausted now and we can close this discussion - until Adobe react properly.
Copy link to clipboard
Copied
Friends, it's even worse - I must come back to this discussion.
After just one test I was convinced that at least Line works correctly, but new tests are not positive.
Having these points in the calling rouine
first point drawn | second point | |
var oPoints = [1, 1, 3, 2]; | 1, 1 | 3, 2 |
var oPoints = [2, 4, 9, 2]; | 2, 4 | 9, 4.63500013188259 |
var oPoints = [1.5, 3.5, 9, 2.1]; | 1.5, 3.5 | 9, 4.13499986273445 |
var oPoints = [2,2, 3, 10]; | 2, 2 | 3, 10 |
var oPoints = [2,2, 10, 3]; | 2, 2 | 10, 3 |
var oPoints = [1,4, 10, 1]; | 1, 4 | 10, 4.63500013188259 |
Only the first point is always correctly placed. The end-point of the line is randomly placed!
The script is this:
function DrawLine (oDoc, oFrame, oPoints) { // === Draw a straight line ===
var j, jLast, k, oLine = oDoc.NewLine(oFrame);
jLast = oPoints.length-1; // last index
for (j = 0; j <= jLast; j++) { // convert into internal units
oPoints
= oPoints * CM; }
oLine.BorderWidth = 0.05*CM; // Stroke-width
oLine.LocX = oPoints[0]; // otherwise has
oLine.LocY = oPoints[1]; // precedence over 1st point
oLine.Points = oPoints;
oLine.Width = oPoints[jLast-1] - oPoints[0]; // object dimensions
oLine.Height= oPoints[jLast] - oPoints[1]; // default : 1/4"
oLine.Fill = 0; // full
oLine.Color = 0; // black is anyway default
return oLine;
} //--- end DrawLine
After drawing I use the following script to get the coordinates of the points listed:
// InspectCurrentObject.jsx ==============
// Line or PolyLine object must be selected
#target framemaker
var j, oDoc = app.ActiveDoc, oObject, nPoints, CM = 1857713;
oObject = oDoc.FirstSelectedGraphicInDoc;
nPoints = oObject.NumPoints
for (j = 0; j < nPoints; j++) {
$.writeln (oObject.Points
.x/CM + "\t" + oObject.Points .y/CM); }
Copy link to clipboard
Copied
Hi Klaus,
I did also some tests with that and I think handling graphic objects with Points is very buggy in ESTK.
But with FDK it works perfectly, as I did that in the past with very complex und high requirements.But I also remember some strange Things.
So I think you should switch to FDK or save document as MIF and change MIF in an external process.
But BTW: draw a line by Hand and save doc to MIF. Check the coordinates there and see if you will get the same values, which are senseless on a first view. Perhaps on point of FM view this may correct and you have to calculate point values in a different way.
Markus