Insert Word shape at cursor position - c#

Im looking for a way to insert an MS Word Shape at cursor position. At the moment I have the following code which inserts a shape at a predetermined location:
Microsoft.Office.Interop.Word.Range CurrRange = Globals.ThisAddIn.Application.Selection.Range;
//Get the id of the MS Word shape to be inserted
int shapeId = (int)MsoAutoShapeType.msoShapeRoundedRectangle;
//Get the value of the name attribute from the selected tree view item
string nodeText = treeViewItem.GetAttribute("name");
//Add a new shape to the MS Word designer and set shape properties
var shape = CurrRange.Document.Shapes.AddShape(shapeId, 170, 200, 100, 20);
shape.AlternativeText = String.Format("Alt {0}", nodeText);
shape.TextFrame.ContainingRange.Text = nodeText;
shape.TextFrame.ContainingRange.Font.Size = 8;
The location where the shape gets inserted is hardcoded:
This can be seen from the 2nd and 3rd parameters of the AddShape() method:
170 = position measured in points to the left edge of the autoshape
200 = position measured in points to the top edge of the autoshape
I've had a look at the properties and methods of my Range object but cannot seem to find any which store the position values which I require.

The final parameter to AddShape is an Anchor, which expects a range object. Try passing your range into that:
var shape = CurrRange.Document.Shapes.AddShape(shapeId, 0, 0, 100, 20,CurrRange);
Update: It looks like there is a bug in Word 2010 documents that it doesn't respect the Anchor. Save the document as a .doc file and test again, it does anchor it to the beginning of the paragraph if you do that. The link above is just to the microsoft forums, I could not find the connect bug report for the issue.
A workaround would be to specify the top and left based on the location of the selection:
Microsoft.Office.Interop.Word.Range CurrRange = Globals.ThisAddIn.Application.Selection.Range;
//Get the id of the MS Word shape to be inserted
int shapeId = (int)MsoAutoShapeType.msoShapeRoundedRectangle;
//Get the value of the name attribute from the selected tree view item
string nodeText = "Hello World";
var left = Globals.ThisAddIn.Application.Selection.get_Information(Microsoft.Office.Interop.Word.WdInformation.wdHorizontalPositionRelativeToPage);
var top = Globals.ThisAddIn.Application.Selection.get_Information(Microsoft.Office.Interop.Word.WdInformation.wdVerticalPositionRelativeToPage);
//Add a new shape to the MS Word designer and set shape properties
var shape = CurrRange.Document.Shapes.AddShape(shapeId, left, top, 100, 20);
shape.AlternativeText = String.Format("Alt {0}", nodeText);
shape.TextFrame.ContainingRange.Text = nodeText;
shape.TextFrame.ContainingRange.Font.Size = 8;

Related

Text chunks getting positions as in html?

transform pdf points to pixels, worked correctly:
point-to-pixel = 1/72*300(DPI)
getting each text chunk positions (X,Y) in PDF the Y is calculated from
bottom-to-top, not as in standard html or java Script.
to get the Y value from top-to-down , cause not accurate Y position as in
html style , or win Form style.
how to get the correct Y top-to-down using any Page height, or rect mediaBox
or cropBox or rect textMarging finder ?
the code I used is your example of :
public class LocationTextExtractionStrategyClass : LocationTextExtractionStrategy
{
//Hold each coordinate
public List<RectAndText> myPoints = new List<RectAndText>();
/*
//The string that we're searching for
public String TextToSearchFor { get; set; }
//How to compare strings
public System.Globalization.CompareOptions CompareOptions { get; set; }
public MyLocationTextExtractionStrategy(String textToSearchFor, System.Globalization.CompareOptions compareOptions = System.Globalization.CompareOptions.None)
{
this.TextToSearchFor = textToSearchFor;
this.CompareOptions = compareOptions;
}
*/
//Automatically called for each chunk of text in the PDF
public override void RenderText(TextRenderInfo renderInfo)
{
base.RenderText(renderInfo);
//See if the current chunk contains the text
var startPosition = 0;// System.Globalization.CultureInfo.CurrentCulture.CompareInfo.IndexOf(renderInfo.GetText(), this.TextToSearchFor, this.CompareOptions);
//If not found bail
if (startPosition < 0)
{
return;
}
//Grab the individual characters
var chars = renderInfo.GetCharacterRenderInfos().ToList();//.Skip(startPosition).Take(this.TextToSearchFor.Length)
var charsText = renderInfo.GetText();
//Grab the first and last character
var firstChar = chars.First();
var lastChar = chars.Last();
//Get the bounding box for the chunk of text
var bottomLeft = firstChar.GetDescentLine().GetStartPoint();
var topRight = lastChar.GetAscentLine().GetEndPoint();
//Create a rectangle from it
var rect = new iTextSharp.text.Rectangle(
bottomLeft[Vector.I1],
bottomLeft[Vector.I2],
topRight[Vector.I1],
topRight[Vector.I2]
);
BaseColor curColor = new BaseColor(0f, 0f, 0f);
if (renderInfo.GetFillColor() != null)
curColor = renderInfo.GetFillColor();
//Add this to our main collection
myPoints.Add(new RectAndText(rect, charsText, curColor));//this.TextToSearchFor));
}
}//end-of-txtLocation-class//
You are asking many different questions in one post.
First let's start with the coordinate system in the PDF standard. Observe that I am talking about a standard, more specifically about ISO 32000. The coordinate system on a PDF page is explained in my answer to the Stack Overflow question How should I interpret the coordinates of a rectangle in PDF?
As you can see, a rectangle drawn in a PDF using a coordinate (llx, lly) for the lower-left corner and a coordinate (urx, ury) for the upper-right corner, assumes that the X-axis points to the right, and the Y-axis points upwards.
As for the width and the height of a page, that's explained in my answer to the Stack Overflow question How to Get PDF page width and Height?
For instance: you could have a /MediaBox that is defined as [0 0 595 842], and therefore measures 595 x 842 points (an A4 page), but that has a /CropBox that is defined as [5 5 590 837], which means that the visible area is only 585 x 832 points.
You also shouldn't assume that the lower-left corner of a page coincides with the (0, 0) coordinate. See Where is the Origin (x,y) of a PDF page?
When you create a document from scratch, a default margin of half an inch is used if you don't define a margin yourself. If you want to change the default, see Fit content on pdf size with iTextSharp?
Now for the height of a Chunk or, if you're using iText 7 (which you should, but —for some reason unknown to me— don't) the height of a Text object, this depends on the font size. The font size is an average size of the different glyphs in a font. If you look at the letter g, and you compare it with the letter h, you see that g takes more space under the baseline of the text than h, whereas h takes more space above the baseline than g.
If you want to calculate the exact space that is taken, read my answer to the question How to calculate the height of an element?
If the text snippet is used in the context of lines in a paragraph, you also have to take the leading into account: Changing text line spacing (Maybe that's not relevant in the context of your question, but it's good to know.)
If you have Chunk objects in iText 5, and you want to do specific things with these Chunks, you might benefit from using page events. See How to draw a line every 25 words?
If you want to add a colored background to a Chunk, it's even easier: How to set the paragraph of itext pdf file as rectangle with background color in Java
Update 1: All of the above may be irrelevant if you are looking to convert HTML to PDF. In that case, it's easy: use iText 7 + pdfHTML as described in Converting HTML to PDF using iText and all the Math is done by the pdfHTML add-on.
Update 2: There seems to be some confusion regarding the measurement units. The differences between user units, points and pixels is explained in the FAQ page How do the measurement systems in HTML relate to the measurement system in PDF?
Summarized:
1 in. = 25.4 mm = 72 user units by default (but it can be changed).
1 in. = 25.4 mm = 72 pt.
1 in. = 25.4 mm = 96 px.

C# MSChart - charts area limits

I have one Chart and three ChartArea that are aligned in view, zoom, cursor:
this is my related previous post. All things works well except that the three ChartArea are not aligned at the beginning. Following an image of the problem:
I think it depends from the digit's number of Y values axis. From some research I try the following configuration:
// selezione e zoom
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.Interval = 1;
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.IsUserEnabled = true;
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.IsUserSelectionEnabled = true;
// generale
dlChart.ChartAreas[VOLTAGE_AREA].AxisX.LabelStyle.Format = "dd/MM/yy - HH:mm:ss.fff";
dlChart.ChartAreas[VOLTAGE_AREA].AxisX.ScaleView.Zoomable = true;
dlChart.ChartAreas[VOLTAGE_AREA].AxisY.LabelStyle.Format = "D5";
In witch the last row:
dlChart.ChartAreas[VOLTAGE_AREA].AxisY.LabelStyle.Format = "D5";
should specifies always five digits. This mitigate in some way the problem but it doesn't desappers. Furthermore with this row the program starts to throws very lots exceptions of form below any time I scroll the graph:
Generate exception: 'System.FormatException' in mscorlib.dll
Does anyone knows the solution for this problem? Thanks in advance.
You may want to take control of the size of the InnerPlotPosition.
(But Baddack's solution is simpler and more flexible!)
Here is an example:
After setting up a Chart with three CharAreas, setting Minima and Maxima as well as adding one DataPoint to each we get this :
Your issue is showing clearly.
After setting the InnerPlotPosition to a fixed percentage it looks like this:
Here is how to set the InnerPlotPosition size:
ca1.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
ca2.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
ca3.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
Note that both ChartArea.Position and ChartArea.InnerPlotPosition are called 'Position' but really are areas of percentages referring to the respective containers!
So my example has a Left distance of 10%, a Top space of 5% and Width of 80% and Height of 90%. Which leaves 10% space at the Bottom and 5% at the Right. Note: All are referring to the ChartAreas not the ClientArea of the Chart! (Which are still at Auto, which maximizes the size.)
This was my initial setup:
ChartArea ca1 = chart.ChartAreas[0];
ChartArea ca2 = chart.ChartAreas[1];
ChartArea ca3 = chart.ChartAreas[2];
Series s1 = chart.Series[0];
Series s2 = chart.Series.Add("Series2");
Series s3 = chart.Series.Add("Series3");
s2.ChartArea = ca2.Name;
s3.ChartArea = ca3.Name;
s1.Points.AddXY(1, 7);
s2.Points.AddXY(1, 777);
s3.Points.AddXY(1, Math.PI);
Have you tried using the chart area alignment options? I would try something like:
//define inner plot position of the chart areas
dlChart.ChartAreas[0].InnerPlotPosition.Auto = true;
dlChart.ChartAreas[1].InnerPlotPosition.Auto = true;
dlChart.ChartAreas[2].InnerPlotPosition.Auto = true;
//set our second chart area's alignments to match our first chart area
dlChart.ChartAreas[1].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
dlChart.ChartAreas[1].AlignmentStyle = AreaAlignmentStyles.All;
dlChart.ChartAreas[1].AlignWithChartArea = dlChart.ChartAreas[0].Name;
//set our third chart area's alignments to match our first chart area
dlChart.ChartAreas[2].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
dlChart.ChartAreas[2].AlignmentStyle = AreaAlignmentStyles.All;
dlChart.ChartAreas[2].AlignWithChartArea = dlChart.ChartAreas[0].Name;

SoftArtisans: Text Orientation within a Shape

I am attempting to create a diagram using SoftArtisans' ExcelApplication, Anchor and Shape.
I am able to get shapes to appear on my output file; however, I have a requirement that the text shown in the Shape must read bottom to top, i.e. SHAPE must be shown as:
E
P
A
H
S
I am creating my shapes on the file using the following code, which exists in a for loop:
if (prevRow != null && prevRow.FixtureY != pogPicDtl.FixtureY)
{
currRow += 3;
currCol = 0;
}
double prodX = (double)pogPicDtl.PositionX;
double prodY = (double)pogPicDtl.PositionY;
Shapes sheetShapes = wb.Worksheets[sheetNumber].Shapes;
Anchor anchor = wb.Worksheets[sheetNumber].CreateAnchor(currRow, currCol, prodX * .1, prodY );
Shape box = sheetShapes.CreateShape(ShapeType.Rectangle, anchor);
box.FillColor = blue;
box.FillTransparency = 0.50;
box.Height =(double) pogPicDtl.PositionHeight *10;
box.Width = (double)pogPicDtl.PositionWidth*10;
// I want this Text to read upw
box.Text = Math.Round(pogPicDtl.PositionX,0).ToString() + "," + Math.Round(pogPicDtl.PositionY,0).ToString();
Is this possible with SoftArtisans? It is certainly possible when using Excel just on its own, but through the API, I have yet to find the text orientation to be modifiable when it is relating to a Shape.
According to http://wiki.softartisans.com/display/EW9/Shape this property is not currently supported. However ExcelWriter preserves most settings. Is it possible to have the shape with the text rotation already set in your input file, and just change the text.
Another option, depending on the shape, might be to just set shape rotation http://wiki.softartisans.com/display/EW9/Shape.Rotation so that the text appears to be read upwards.

C# EPPLUS Chart SetPosition Method Row Offset does not work

I am creating a chart to export to excel. I need to create several, so I would offset them using the SetPosition() method with the 4 parameters:
SetPosition(int row, int rowoffset in pixel, int col, int coloffset in pixel)
thus
chart.SetPosition(startRow, 350*i, 0, 50);
The problem is that the second row offset parameter stretches the chart by 350*i pixels higher. This must be a bug since the col offset 4th parameter works fine and as expected.
I need to use startRow to start at a specific row cell in the sheet, so I need to get the row offset to work somehow.
Any ideas?
The RowOffset and ColumnOffset have given me trouble as well and I avoid using them in that function. If you look at the source could you can see it doing alot of match with the chart height/width so it seems to do more then just set and top/left position. I have not gone through the effort to fully reverse engineer it.
I just do the math myself. Knowing the default row height in pixels is the only thing that you have to watch out for since this can be customized by the user which you cannot know at design time Here is what I do:
using (var pck = new ExcelPackage(fi))
{
var workbook = pck.Workbook;
var worksheet = workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromDataTable(datatable, true);
//Set specific values to make predictable
const int EXCELCHARTWIDTH = 375;
const int EXCELCHARTHEIGHT = 350;
//Have to assume a standard screen dpi but can be customized by the user
const double EXCELDEFAULTROWHEIGHT = 20.0;
var startCell = (ExcelRangeBase)worksheet.Cells["A1"];
for (var i = 0; i < 10; i++)
{
var chart = worksheet.Drawings.AddChart("chart " + i, eChartType.Pie);
chart.SetSize(EXCELCHARTWIDTH, EXCELCHARTHEIGHT);
chart.SetPosition(startCell.Start.Row, 0, startCell.Start.Column, 0);
var chartcellheight = (int)Math.Ceiling(EXCELCHARTHEIGHT / EXCELDEFAULTROWHEIGHT);
startCell = startCell.Offset(chartcellheight, 0);
}
pck.Save();
}
The offset is an offset within one cell.
So if you have a cell 64 x 20 pixels (default) it should not usually exceed 64 or 20 resp. To set the top left corner of a chart just in the middle of a cell, call:
chart.SetPosition(row , 10, col, 32);
also note that if you read the position from From.RowOff, you need to divide it by 9525

C# Revit API, CreateIndependentTag method failing to add tag to ceilings, exception at line location point

This code attempts to add a tag to all ceilings in the ceiling views list. The ceiling view list populates and I can get the ceiling elements from the document, but it seems to be failing when trying to acquire the centre point of the ceiling element. I have googled all the blogs and I cant find a reference to tagging floors in revit either as it may be a similar scenario.
public IndependentTag CreateIndependentTag(Document doc)
{
List<View> viewList = ceilingViewCollector(doc);
foreach (View view in viewList)
{
// Find all ceiling elements in the document by using category filter
ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_Ceilings);
// Use shortcut WhereElementIsNotElementType() to find ceiling instances only
FilteredElementCollector collector = new FilteredElementCollector(doc);
IList<Element> CeilingList = collector.WherePasses(filter).WhereElementIsNotElementType().ToElements();
foreach (Ceiling ceiling in CeilingList)
{
TaskDialog.Show("Ceiling", ceiling.Name);
// define tag mode and tag orientation for new tag
TagMode tagMode = TagMode.TM_ADDBY_CATEGORY;
TagOrientation tagorn = TagOrientation.Horizontal;
//add tag to centre of ceiling?
LocationPoint p = ceiling.Location as LocationPoint;
p.Point = new XYZ(0.0, p.Point.Y, p.Point.Z);
ceilingCentre = p.Point;
string coords = "point = " + ceilingCentre.ToString();
TaskDialog.Show("Source room Center", coords);
IndependentTag newTag = doc.Create.NewTag(view, ceiling, true, tagMode, tagorn, ceilingCentre);
if (null == newTag)
{
throw new Exception("Create IndependentTag Failed.");
}
// set leader mode free
// otherwise leader end point move with elbow point
newTag.LeaderEndCondition = LeaderEndCondition.Free;
XYZ elbowPnt = ceilingCentre + new XYZ(5.0, 5.0, 0.0);
newTag.LeaderElbow = elbowPnt;
XYZ headerPnt = ceilingCentre + new XYZ(10.0, 10.0, 0.0);
newTag.TagHeadPosition = headerPnt;
return newTag;
}
}
return null;
}
I'm no expert but, aren't you forgetting your X-component?
//add tag to centre of ceiling?
LocationPoint p = ceiling.Location as LocationPoint;
p.Point = new XYZ(p.Point.X / 2, p.Point.Y / 2, p.Point.Z);
ceilingCentre = p.Point;
It would seem you'd want to center this Point p in terms of X and Y, and keep the Z component.
A little late but I just ran across this. Revit elements can be located by a point (most family instances), a line (walls, line based components), or a sketch (ceilings, floors, etc.). Your code will not work because you are casting the location to a location point and it isn't a location point.
With sketches you can't cast the location to anything useful so you will need to figure out how you want to determine the center of the ceiling on your own. The simple answer is to find the bounding box of the ceiling and calculate it's center as suggested by mtumminello. This will work for most ceilings except if you have a large L shape or something the bounding box center may not be over the ceiling at all. If you need this covered you would have to come up with some other algorithm to find the center point.

Categories