Using iText7, what represent a line having negative coordinates? - pdf

I written a VB.Net program that intercept RENDER_PATH events generated by iText7 module.
I have written a little code to display X and Y coordinates of lines in segment.
Dim iNrPaths As Integer = 0
Dim iNrSubPaths As Integer = 0
Dim iNrSegments As Integer = 0
Dim iNrLines As Integer = 0
For Each oPath As PathRenderInfo In listener.getPaths()
Dim m As Matrix = oPath.GetCtm()
iNrPaths += 1
Dim iLineWidth = oPath.GetLineWidth()
sw.WriteLine("Render.LINE-WIDTH: " & CStr(iLineWidth))
For Each sp As Subpath In oPath.GetPath().GetSubpaths()
iNrSubPaths += 1
sw.WriteLine(oPath.GetPath().ToString())
For Each segment In sp.GetSegments()
iNrSegments += 1
sw.WriteLine(" " & segment.ToString())
Select Case segment.GetType()
Case GetType(iText.Kernel.Geom.Line)
iNrLines += 1
Dim oLine As iText.Kernel.Geom.Line = segment
Dim oList As List(Of Point) = oLine.GetBasePoints()
Dim n = 0
For Each p In oList
sw.WriteLine(" p" & CStr(n) & ".x: " & oList(n).GetX().ToString("0.####"))
sw.WriteLine(" p" & CStr(n) & ".y: " & oList(n).GetY().ToString("0.####"))
n += 1
Next
sw.WriteLine(" width: " & CStr(oList(0).GetX() - oList(1).GetX()))
sw.WriteLine(" height: " & CStr(oList(0).GetY() - oList(1).GetY()))
Case GetType(iText.Kernel.Geom.BezierCurve)
Case Else
Dim i0 = 0
End Select
Next
Next
Next
Normally, the majority of lines have positives X and Y coordinates.
Example:
Render.LINE-WIDTH: 9,50001
iText.Kernel.Geom.Path
iText.Kernel.Geom.Line
p0.x: 1818,9301
p0.y: 1475,79
p1.x: 2365,02
p1.y: 1475,79
width: -546,089965820313
height: 0
iText.Kernel.Geom.Line
p0.x: 2365,02
p0.y: 1475,79
p1.x: 2365,02
p1.y: 2298,3989
width: 0
height: -822,60888671875
iText.Kernel.Geom.Line
p0.x: 2365,02
p0.y: 2298,3989
p1.x: 1818,9301
p1.y: 2298,3989
width: 546,089965820313
height: 0
But some times, I can see NEGATIVE location values !
Example
Render.LINE-WIDTH: 12,5
iText.Kernel.Geom.Path
iText.Kernel.Geom.Line
p0.x: -99,2109
p0.y: 8192,1396
p1.x: -249,215
p1.y: 8192,1396
width: 150,004096984863
height: 0
iText.Kernel.Geom.Path
iText.Kernel.Geom.Line
p0.x: 6051,98
p0.y: 8192,1396
p1.x: 6201,98
p1.y: 8192,1396
width: -150
height: 0
iText.Kernel.Geom.Path
iText.Kernel.Geom.Line
p0.x: -99,2109
p0.y: -0,0039
p1.x: -249,215
p1.y: -0,0039
width: 150,004096984863
height: 0
What do represent such lines ?
What is a line between 2 points having negative X and Y coordinates ?
Is there a bug/failure in my VB.Net program that is displaying theses values ?

What is a line between 2 points having negative X and Y coordinates ?
It's just a regular line. Why shouldn't there be negative coordinate values?
Real valued coordinate systems usually have an origin (all coordinates 0) in which all coordinate axes intersect. On each axis in one direction from the origin you have negative coordinate values and in the other diction you have positive ones.
The coordinates in the visible section of a PDF page are defined by the crop box of a page. And while it is common to have the origin in the lower left corner of that box and only non-negative coordinates in the crop box, this is not required. The origin can also be in the upper right corner, for example, with only non-positive coordinate values in the visible page.
Furthermore, a line can go from some point outside the visible area to some other point outside but nonetheless intersect the visible part.
And a third remark, you retrieve the CTM but you do not apply it to the coordinates. The CTM may also change the current coordinate system to something with unexpected coordinate values.
You might want to read up on the coordinates in PDFs in the PDF specification, ISO 32000. For starters the old part 1 should suffice: https://adobe.com/go/pdfreference

Related

How to show dimensions of objects - autocad

I have multi shapes.
I want to show all dimensions of each sides(the green lines).
I want to use vba.
I can show dimension a full square or rectangle shape.
for example to show a horizontal dimension I use this function:
Function createDimensionHorizental(x1, y1, x2, y2)
' This example creates an aligned dimension in model space and
' uses the TextHeight property to increase the height of the
' dimension text
Dim dimObj As AcadDimAligned
Dim point1(0 To 2) As Double, point2(0 To 2) As Double
Dim location(0 To 2) As Double
' Define the dimension
point1(0) = x1: point1(1) = y1: point1(2) = 0
point2(0) = x2: point2(1) = y1: point2(2) = 0
location(0) = x1: location(1) = y1 + 10: location(2) = 0
' Create an aligned dimension object in model space
Set dimObj = ThisDrawing.ModelSpace.AddDimAligned(point1, point2, location)
' Read and display current dimension text height
'MsgBox "The dimension text height for this object is currently set to: " & dimObj.TextHeight
' Increase the distance of the dimension gap
'Format the dimension object according to your needs.
With dimObj
.TextHeight = 30
.TextGap = 10 'The distance of the dimension text from the dimension line.
.Arrowhead1Type = 5 'acArrowOblique in early binding
.Arrowhead2Type = 5 'For the standard dimension arrow put 0 here.
.ArrowheadSize = 20
.ExtensionLineExtend = 10 'The amount to extend the extension line beyond the dimension line.
End With
ThisDrawing.Regen acAllViewports
End Function

Using iText7.Net, why dimensions returned by iText.Kernel.Geom.Point are 10 times greater that TextRenderInfo.LineSegment.GetStartPoint()?

I written a VB.Net program that intercept RENDER_PATH and RENDER_TEXT events generated by iText7 module.
I have written a little code to find location of TEXT.
Dim ascent As LineSegment = t.GetAscentLine()
Dim descent As LineSegment = t.GetDescentLine()
Dim initX As Single = descent.GetStartPoint().Get(0)
Dim initY As Single = descent.GetStartPoint().Get(1)
Dim endX As Single = ascent.GetEndPoint().Get(0)
Dim endY As Single = ascent.GetEndPoint().Get(1)
For specific PDF page, all values returned by GetStartPoint() and GetEndPoint() are between 20 and 600.
To find PATH values, I have writte following code
Private Sub RenderPath(render As PathRenderInfo)
For Each sp As Subpath In render.GetPath().GetSubpaths()
Console.WriteLine(render.GetPath().ToString())
For Each segment In sp.GetSegments()
Console.WriteLine(" " & segment.ToString())
Select Case segment.GetType().FullName
Case "iText.Kernel.Geom.Line"
Dim oLine As iText.Kernel.Geom.Line = segment
Dim oList As List(Of Point) = oLine.GetBasePoints()
Dim n = 0
For Each p In oList
Console.WriteLine(" p" & CStr(n) & ".x: " & CStr(oList(n).GetX()))
Console.WriteLine(" p" & CStr(n) & ".y: " & CStr(oList(n).GetY()))
n += 1
Next
Console.WriteLine(" width: " & CStr(oList(0).GetX() - oList(1).GetX()))
Console.WriteLine(" height: " & CStr(oList(0).GetY() - oList(1).GetY()))
Case "iText.Kernel.Geom.BezierCurve"
Case Else
Dim i0 = 0
End Select
Next
Next
End Sub
All location's values returned by GetX() and GetY() functions are now between ... 200 and 6000 !
Why PATH location's values seems to be 10 times greater that TEXT location's values ?
Is that normal or is that a BUG ?
In iText7, what are dimensions of TEXT locations and dimensions of PATH segments ?
In iText7, what are dimensions of TEXT locations and dimensions of PATH segments ?
Indeed, the coordinates returned by TextRenderInfo and those returned by PathRenderInfo differ:
Coordinates returned by TextRenderInfo are given in the default user space coordinates of the given page, i.e. all active transformations are already accounted for.
Coordinates returned by PathRenderInfo, on the other hand, are given in the current user space coordinates - current when the path is constructed and drawn. To transform these coordinates into default user space coordinates, you have to apply the CTM (current transformation matrix) to the path. You can retrieve the CTM using the GetCTM method of the path render info object.
That different render info classes return coordinates in conceptually different coordinate system probably isn't intuitive and should be made clearer.
In case of your document page the CTM appears to be a scaling transformation by a factor of 0.1.

How do I move around nodes in a shape?

I am trying to create a Sankey-diagram in Excel, and as a start to this, I am trying to create some "entry arrows" for the left part of the diagram, which will look roughly like this:
I created it by making a chevron arrow, and dragging the rightmost points of it to line up with the tip of the arrow.
Now, to do this for all the arrows I need, I want to do this programmatically, but I can't figure out if there is any way to do much with the nodes (?) of the shape. Trying to record a macro gave me nothing.
This is what I have so far, the macro aborts on the Debug.Print line, probably because the node object doesn't have a Left property :P
Sub energiInn()
Dim r As Range, c As Range
Dim lo As ListObject
Dim topp As Double, høgde As Double
Dim i As Long, farge As Long
Dim nd As Object
Set lo = Tabell.ListObjects("Energi_inn_elektrolyse")
Set r = lo.DataBodyRange
topp = 50
With SankeyDiagram.Shapes
For i = 1 To r.Rows.Count
høgde = Application.WorksheetFunction.Max(10, r.Cells(i, 2) / 50#)
With .AddShape(Type:=msoShapeChevron, Left:=50, top:=topp, Width:=200, Height:=høgde)
.Name = r.Cells(i, 1)
farge = fargekart((i - 1) Mod UBound(fargekart))
.Fill.ForeColor.RGB = RGB(farge Mod 256, (farge \ 256) Mod 256, farge \ 65536)
For Each nd In .Nodes
Debug.Print nd.Left
Next nd
End With
topp = topp + høgde
Next i
End With
Debug.Print r.Address
End Sub
Honestly, I am unsure if this can be done at all, but even if it is impossible, it would be nice to get it confirmed :)
What you're looking for is .Nodes.SetPosition. Because it's relative positioning, this can be a challenge. You need to use the objects position elements to make sure the points are moving in relation to the shape.
With .AddShape(Type:=msoShapeChevron, Left:=50, Top:=topp, Width:=200, Height:=høgde)
.Name = r.Cells(i, 1)
.Nodes.SetPosition 2, .Left + .Width, .Top
.Nodes.SetPosition 4, .Left + .Width, .Top + .Height
First argument is the node index. Next is the x position, which we want all the way to the right of the graphic, so we add the shapes position left to the width of the shape. Last is the y position, first point we want in the topmost corner, so we use the shapes top. Last point, we add the height to the top position to bring to the bottom corner.
I believe it would be more simple drawing this as free form using Shapes.BuildFreeform Method and then converting to shape using FreeformBuilder.ConvertToShape Method.
Example:
Sub drawEntryArrow()
Dim x1 As Single, y1 As Single, w As Single, h As Single
Dim oShape As Shape
x1 = 10
y1 = 10
w = 200
h = 200
With ActiveSheet.Shapes.BuildFreeform(msoEditingAuto, x1, y1)
.AddNodes msoSegmentLine, msoEditingAuto, x1 + w, y1
.AddNodes msoSegmentLine, msoEditingAuto, x1 + w, y1 + h
.AddNodes msoSegmentLine, msoEditingAuto, x1, y1 + h
.AddNodes msoSegmentLine, msoEditingAuto, x1 + w / 2, y1 + h / 2
.AddNodes msoSegmentLine, msoEditingAuto, x1, y1
Set oShape = .ConvertToShape
End With
End Sub
If you just want to get rid of the point at the right, you can simply delete the node (nodes of a chevron are counted clockwise starting at the top left):
.Nodes.Delete 3
To get access to all nodes with the nodes-property of a shape, however, as long as you deal with a standard shape type, you can't access the coordinates.
When you use the "edit points", a shape changes its type to msoShapeNotPrimitive - but I couldn't figure out how to do this using VBA.
UPDATE
Played around a bit (because I'm curious) - just as an example if someone wants to change a shape manually:
' First change Shape Type:
' WILL NOT WORK: sh.AutoShapeType = msoShapeNotPrimitive
' Instead, add a node and remove it immediately. This changes the shape type.
.Nodes.Insert c, msoSegmentLine, msoEditingCorner, 100, 100
.Nodes.Delete c + 1
' Now access the x-coordinate of node 2 and the y-coordinate of node 3
' (note that we cannot access the coordinates directly)
Dim pointsArray() As Single, x As Single, y As Single
pointsArray = .Nodes(2).Points
x = pointsArray(1, 1)
pointsArray = .Nodes(3).Points
y = pointsArray(1, 2)
' Now change the x-value of node 3
sh.Nodes.SetPosition 3, x, y

Increment the length of a copied motion path using VBA

I am trying to create a row of duplicated objects in PowerPoint, each with a motion path that is slightly shorter than the next, like this:
First Image
I know that you cannot add a path animation from scratch in VBA, so I used VBA to copy and paste an object and its motion path, then edit the motion path.
This is my VBA code:
Sub CopyPastePosition()
' Copy the shape in slide 2 which has a custom motion path aleady
ActivePresentation.Slides(2).Shapes(3).Copy
Dim x As Integer
' For loop - create 5 duplicates
For x = 1 To 5
' Each duplicate is nudged to the left by x*100
With ActivePresentation.Slides(1).Shapes.Paste
.Name = "Smiley"
.Left = x * 100
.Top = 1
End With
' This is where I am unsure - I want the motion path to be longer by x amount each time
ActivePresentation.Slides(1).TimeLine.MainSequence(x).Behaviors(1).MotionEffect.Path = "M 0 0 L 0 x*0.7"
Next x
End Sub
However, the output is like this:
Second Image
Path property for motion path which represents a VML string. The VML string is a collection of coordinates for a Line or Bezier curve (for
powerpoint purposes). The values are fractions of the slide dimensions.
You can generate an incrementing VML path with this function.
Function GetPath(MaxSegments As Integer, Increment As Single)
Dim path As String
Dim i As Integer
path = "M 0 0 "
For i = 1 To MaxSegments
path = path & "L 0 " & CStr(Increment * i) & " "
Next
path = path & " E"
GetPath = path
End Function
Since you are doing copy/paste of a shape with motion path already on it, I would also make this change to ensure we reference the correct motion path upon paste:
With ActivePresentation.Slides(1).TimeLine
.MainSequence(.MainSequence.Count).Behaviors(1).MotionEffect.path = GetPath(x, 0.7)
End With
Yes, I realise that I am trying to insert a variable into a string. yes the correct way of doing this is "M 0 0 L 0 " & (x * 0.7)
Thank you #braX

Show mouse's position on a logarithmic axis on a chart in vb.net

I'm working with a MSchart and I'm trying to figure out how to show the x-axis value based on the mouse's position in the graph. It only shows when the mouse is on a datapoint. The y-axis is scaled linearly and works as it should.
The x-axis however doesn't since it is logarithmic and gives me results this:
(0 = 0, 10 = 1, 100 = 2, 1000 = 3)
Where x = 10, it gives me a returned value of 1, where x = 100, it gives me a returned value of 2, and etc.
dim position = e.Location
dim result = myChart.hitTest(position.x, position.y)
etoolTip.active = true
if(result.ChartElementType = DataVisualization.Charting.ChartElementType.datapoint)
dim x = result.ChartArea.AxisX.PixelPositionToValue(position.x)
dim y = result.chartarea.axisy.pixelPositionToValue(position.y)
etoolTip.SetToolTip(phaseNoiseChart, "X:"&x &"Y:"&y)
else
etoolTip.active = false
End If
How do I get the x-axis's true position based on the mouse's position for an axis that is logarithmic?
since the code belongs to mouse move event
e.X will give you the x co-ordinate
e.Y will give you the y co-ordinate
I clearly didn't understand what those numbers meant until I realized what the answer was telling me. The way I turn it back into actual coordinates is by 10^x.
dim x = result.ChartArea.AxisX.PixelPositionToValue(position.x)
x = 10^x
dim y = result.chartarea.axisy.pixelPositionToValue(position.y)
etoolTip.SetToolTip(phaseNoiseChart, "X:"&x & "Y:"&y)