c#, autocad plugins, Updating text of object properties - c#

I need to write AutoCAD plugin to display the area of the object.
Below is my code.
It works fine, but test is static. I need to keep tracking the area of the circle cir.Area.ToString();.
Currently, If I change the size of the circle latter on, the text does not change anymore.
For example, the area of my circle is 10. I run code, it displays 10. But if I change the radius of circle, the text remains 10.
How can I make it working.
[CommandMethod("displayarea")]
public static void Displayarea()
{
var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var filter = new SelectionFilter(new[] { new TypedValue(0, "Circle") });
var selection = ed.GetSelection(filter);
if (selection.Status != PromptStatus.OK)
return;
using (var tr = db.TransactionManager.StartTransaction())
{
var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
foreach (var id in selection.Value.GetObjectIds())
{
var ids = new ObjectIdCollection(new[] { id });
Circle cir = (Circle)tr.GetObject(id, OpenMode.ForRead) as Circle;
var _centerPosition = cir.Center;
using (DBText acText = new DBText())
{
acText.Position = _centerPosition;
acText.TextString = cir.Area.ToString();
acText.Height = 0.5;
curSpace.AppendEntity(acText);
tr.AddNewlyCreatedDBObject(acText, true);
}
}
tr.Commit();
}
}

Also you can use oEntity.Modified += OEntity_Modified;
Find this: Find which properties changed on modified event

You need to use fields.
Find this:
https://www.keanw.com/2007/07/accessing-the-a.html

It works by replacing
cir.Area.ToString();
to
string circarea = "%<\\AcObjProp Object(%<\\_ObjId "
+ CircleId
+ ">%).Area \\f \"%lu2\">%";

Related

ASP.NET MVC Google pie chart controller

I am looking a friends code to implement google charts into my mvc project.
I have a model that I am pulling data from:
public partial class HoursPerSite
{
public string SiteName { get; set; }
public Nullable<decimal> SiteHours { get; set; }
}
The chart has rendered and it looks good but the legend is showing SiteHours and not SiteName as I'd like it to.
Here is the controller part:
// HOLIDAY PIE START
ViewBag.msg = db.HoursPerSites.Count().ToString();
var query = from r in db.HoursPerSites
select new { Count = r.SiteHours, Value = r.SiteHours };
var result2 = query.ToList();
var datachart2 = new object[result2.Count];
int l = 0;
foreach (var i in result2)
{
datachart2[l] = new object[] { i.Value.ToString(), i.Count };
l++;
}
string datastr2 = JsonConvert.SerializeObject(datachart2, Formatting.None);
ViewBag.dataj2 = new HtmlString(datastr2);
// HOLIDAY PIE END
I'd like it so the pie chart legend/key shows the site not the hours.
Not sure but is this:
select new { Count = r.SiteHours, Value = r.SiteHours };
Not supposed to be this: (SiteName):
select new { Count = r.SiteHours, Value = r.SiteName };
Also, your naming is very bad if I may say. That will not make your future work easier. Try naming your variables and obejects more specifically.
EDIT:
You can make use of Regions instead of code comments for example which will make seperation/ordering/viewing of code parts/sections much easier
Naming your variables better will make your life but also other
people working on/with your code easier
I would change your current code to this:
Please note that I don't have any editor and that there could be syntax errors
#region Holiday Pie Chart
ViewBag.msg = db.HoursPerSites.Count().ToString();
var queryHoursPerSites = from r in db.HoursPerSites
select new { Count = r.SiteHours, Value = r.SiteHours };
var resultsQueryHoursPerSites = queryHoursPerSites.ToList(); // or HoursPerSitesCollection
var holidayPieChart = new object[resultsQueryHoursPerSites.Count];
int counter = 0; //
foreach (var record in resultsQueryHoursPerSites)
{
holidayPieChart[counter] = new object[] { record.Value.ToString(), record.Count };
counter++;
}
string deserialisedResults = JsonConvert.SerializeObject(holidayPieChart, Formatting.None);
// no idea what dataj2 is here ...
ViewBag.dataj2 = new HtmlString(deserialisedResults);
#endregion
I am sure there is even more to "improve" or "change" but that would in my opinion already be an improvement.
I am sure others can elaborate even better on what I am suggesting here :)

Selecting a POI on Map using a cluster

I am currently using the Map Sample from Microsoft. This sample creates clusters of pins on the map to save space.
I am finding it difficult to be able to select a POI that is on the map and get the properties of the POI.
There are over 1000, POIs so I need clustering, but the sample is not clear on how to select the POI in question.
Code is below:
private async Task LoadPlaceInfoAsync()
{
Uri dataUri = new Uri("ms-appx:///places.txt");
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(dataUri);
IList<string> lines = await FileIO.ReadLinesAsync(file);
// In the places.txt file, each place is represented by three lines:
// Place name, latitude, and longitude.
for (int i = 0; i < lines.Count; i += 3)
{
PlaceInfo place = new PlaceInfo
{
Name = lines[i],
Location = new PlaceLocation(double.Parse(lines[i + 1]), double.Parse(lines[i + 2]))
};
places.Add(place);
}
}
private void refreshMapIcons()
{
// Erase the old map icons.
myMap.MapElements.Clear();
// Create an icon for each cluster.
foreach (var cluster in GetClustersForZoomLevel(previousZoomLevel))
{
MapIcon mapIcon = new MapIcon
{
Location = new Geopoint(cluster.Location.Geoposition),
CollisionBehaviorDesired = MapElementCollisionBehavior.RemainVisible,
};
if (cluster.Places.Count > 1)
{
// The cluster represents more than one place. Use a custom marker that shows
// how many places are represented by this cluster, and place the marker
// centered at the cluster.
mapIcon.Image = numberIconReferences[Math.Min(cluster.Places.Count, 9) - 2];
mapIcon.NormalizedAnchorPoint = new Point(0.5, 0.5);
}
else
{
// The cluster represents a single place. Label the cluster with the place name.
mapIcon.Title = cluster.Places[0].Name;
}
myMap.MapElements.Add(mapIcon);
}
}

visio insertlistmember in C#

Does anyone know how to use the visio insertListMember method (below) in c#?
https://msdn.microsoft.com/en-us/library/office/ff768115.aspx
I have tried to execute the method with the following commands but it gives a "Run Time Error- 424 object required"
I have also used the dropIntoList method and it works fine but for specific purposes I need to use the insertListMember method. (to determine the height of the list)
static void Main(string[] args)
{
//create the object that will do the drawing
visioDrawing.VisioDrawer Drawer = new visioDrawing.VisioDrawer();
Drawer.setUpVisio();
Visio.Shape testShape;
Visio.Shape testShape1;
testShape = Drawer.DropShape("abc", "lvl1Box");
testShape1 = Drawer.DropShape("ccc", "Capability");
Drawer.insertListMember(testShape, testShape1, 1);
}
public void insertListMember(Visio.Shape outerlist, Visio.Shape innerShape, int position)
{
ActiveDoc.ExecuteLine(outerlist + ".ContainerProperties.InsertListMember" + innerShape + "," + position);
}
To obtain the shape:
public Visio.Shape DropShape(string rectName, string masterShape)
{
//get the shape to drop from the masters collection
Visio.Master shapetodrop = GetMaster(stencilPath, masterShape);
// drop a shape on the page
Visio.Shape DropShape = acPage.Drop(shapetodrop, 1, 1);
//put name in the shape
Visio.Shape selShape = selectShp(DropShape.ID);
selShape.Text = rectName;
return DropShape;
}
private Visio.Master GetMaster(string stencilName, string mastername)
{
// open the page holding the masters collection so we can use it
MasterDoc = MastersDocuments.OpenEx(stencilName, (short)Visio.VisOpenSaveArgs.visOpenDocked);
// now get a masters collection to use
Masters = MasterDoc.Masters;
return Masters.get_ItemU(mastername);
}
From your code, 'Drawer' looks to be some kind of Visio app wrapper, but essentially InsertListMember allows you to add shapes to a list that already exist on the page. Here's an example of the method and an alternative Page.DropIntoList if you just want to drop directly from the stencil:
void Main()
{
// 'GetRunningVisio' as per
// http://visualsignals.typepad.co.uk/vislog/2015/12/getting-started-with-c-in-linqpad-with-visio.html
// but all you need is a reference to the app
var vApp = MyExtensions.GetRunningVisio();
var vDoc = vApp.Documents.Add("wfdgm_m.vstx");
var vPag = vDoc.Pages[1];
var vCtrlsStencil = vApp.Documents["WFCTRL_M.VSSX"];
var vListMst = vCtrlsStencil?.Masters["List box"];
if (vListMst != null)
{
var vListShp = vPag.Drop(vListMst, 2, 6);
var vListItemMst = vCtrlsStencil.Masters["List box item"];
var insertPosition = vListShp.ContainerProperties.GetListMembers().Length - 1;
//Use InsertListMember method
var firstListItem = vPag.Drop(vListItemMst, 4, 6);
vListShp.ContainerProperties.InsertListMember(firstListItem, insertPosition);
firstListItem.CellsU["FillForegnd"].FormulaU = "3"; //Green
//or use DropIntoList method on Page instead
var secondListItem = vPag.DropIntoList(vListItemMst, vListShp, insertPosition);
secondListItem.CellsU["FillForegnd"].FormulaU = "2"; //Red
}
}
This is using the Wireframe Diagram template (in Visio Professional) and should result in the following:
In case people were wondering I ended up fixing the method up. However I believe that this method is not required if you are using visio Interop assemblies v15. (I am using v14)
public void insertListMember(int outerShpID, int innerShpID, int position)
{
acWindow.DeselectAll();
Visio.Page page = acWindow.Page;
acWindow.Select(page.Shapes.get_ItemFromID(innerShpID), (short)Microsoft.Office.Interop.Visio.VisSelectArgs.visSelect);
Debug.WriteLine("Application.ActivePage.Shapes.ItemFromID(" + outerShpID + ").ContainerProperties.InsertListMember ActiveWindow.Selection," + position);
ActiveDoc.ExecuteLine("Application.ActivePage.Shapes.ItemFromID(" + outerShpID + ").ContainerProperties.InsertListMember ActiveWindow.Selection," + position);
}

C# - OpenXML SDK 2.5 - Insert New Slide from Slide Masters with the layout that contains images

I used this to create my new slides with the help of the OpenXML 2.5 SDK.
I designed and used my own Slide Master to create a new slide. My Slide Master includes some layouts with images and some layouts without images.
If I create a slide from my Master Layout without images, everything works fine. If I create a slide with the layout, that contains images, I get the right layout BUT on top of every fixed images there is another movable image overlapping the fixed one, so there are unnecessary duplicates of fixed images, that I don't need in my new created slide.
How can I solve this problem?
My code is below:
public static void InsertNewSlide(string presentationFile, int position, string layoutName)
{
using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
{
InsertNewSlide(presentationDocument, position, layoutName);
}
}
public static void InsertNewSlide(PresentationDocument presentationDocument, int position, string layoutName)
{
PresentationPart presentationPart = presentationDocument.PresentationPart;
OpenXML.Slide slide = new OpenXML.Slide(new CommonSlideData(new ShapeTree()));
SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
slide.Save(slidePart);
SlideMasterPart slideMasterPart = presentationPart.SlideMasterParts.First();
SlideLayoutPart slideLayoutPart = slideMasterPart.SlideLayoutParts.SingleOrDefault(sl => sl.SlideLayout.CommonSlideData.Name.Value.Equals(layoutName, StringComparison.OrdinalIgnoreCase));
slidePart.AddPart<SlideLayoutPart>(slideLayoutPart);
slidePart.Slide.CommonSlideData = (CommonSlideData)slideMasterPart.SlideLayoutParts.SingleOrDefault(sl => sl.SlideLayout.CommonSlideData.Name.Value.Equals(layoutName)).SlideLayout.CommonSlideData.Clone();
using (Stream stream = slideLayoutPart.GetStream())
{
slidePart.SlideLayoutPart.FeedData(stream);
}
foreach (ImagePart iPart in slideLayoutPart.ImageParts)
{
ImagePart newImagePart = slidePart.AddImagePart(iPart.ContentType, slideLayoutPart.GetIdOfPart(iPart));
newImagePart.FeedData(iPart.GetStream());
}
uint maxSlideId = 1;
SlideId prevSlideId = null;
var slideIdList = presentationPart.Presentation.SlideIdList;
foreach (SlideId slideId in slideIdList.ChildElements)
{
if (slideId.Id > maxSlideId)
{
maxSlideId = slideId.Id;
}
position--;
if (position == 0)
{
prevSlideId = slideId;
}
}
maxSlideId++;
SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
newSlideId.Id = maxSlideId;
newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);
presentationPart.Presentation.Save();
}
}
Years later, but to help others - there is no need to copy nodes which are not serving a placeholder function to the new slide being based on the master slide template (including images).
The line
using (Stream stream = slideLayoutPart.GetStream())
{
slidePart.SlideLayoutPart.FeedData(stream);
obviously assumes you are not adding a slide within 1 working stream (that is you have separate streams for reading and writing), and the equivalent line
slidePart.Slide.CommonSlideData = (CommonSlideData)layoutPart.SlideLayout.CommonSlideData.Clone();
Both of these lines of code copy all the master data as an overlay onto the new slide . As an example, run one of the blocks of code from the answers above, open the resulting .pptx file in a presentation manager and delete whatever shapes you see - you will note each item is sitting on top of an identical copy (the master slide version) which you cannot delete. This method therefore bloats the file unnecessarily and makes working with the .pptx messy and not as predicted for the end user.
the code below is working including with images
public static SlidePart AppendNewSlide(PresentationPart presentationPart, SlideLayoutPart masterLayoutPart, out IEnumerable<Shape> placeholderShapes)
{
Slide clonedSlide = new Slide() {
ColorMapOverride = new ColorMapOverride {
MasterColorMapping = new Draw.MasterColorMapping()
}
};
SlidePart clonedSlidePart = presentationPart.AddNewPart<SlidePart>();
clonedSlidePart.Slide = clonedSlide;
clonedSlidePart.AddPart(masterLayoutPart);
clonedSlide.Save(clonedSlidePart);
var masterShapeTree = masterLayoutPart.SlideLayout.CommonSlideData.ShapeTree;
placeholderShapes = (from s in masterShapeTree.ChildElements<Shape>()
where s.NonVisualShapeProperties.OfType<ApplicationNonVisualDrawingProperties>().Any(anvdp=>anvdp.PlaceholderShape != null)
select new Shape()
{
NonVisualShapeProperties = (NonVisualShapeProperties)s.NonVisualShapeProperties.CloneNode(true),
TextBody = new TextBody(s.TextBody.ChildElements<Draw.Paragraph>().Select(p => p.CloneNode(true))) {
BodyProperties = new Draw.BodyProperties(),
ListStyle = new Draw.ListStyle()
},
ShapeProperties = new ShapeProperties()
}).ToList();
clonedSlide.CommonSlideData = new CommonSlideData
{
ShapeTree = new ShapeTree(placeholderShapes) {
GroupShapeProperties = (GroupShapeProperties)masterShapeTree.GroupShapeProperties.CloneNode(true),
NonVisualGroupShapeProperties = (NonVisualGroupShapeProperties)masterShapeTree.NonVisualGroupShapeProperties.CloneNode(true)
}
};
SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;
// Find the highest slide ID in the current list.
uint maxSlideId = slideIdList.Max(c=>(uint?)((SlideId)c).Id) ?? 256;
// Insert the new slide into the slide list after the previous slide.
slideIdList.Append(new SlideId() {
Id = ++maxSlideId,
RelationshipId = presentationPart.GetIdOfPart(clonedSlidePart)
});
//presentationPart.Presentation.Save();
return clonedSlidePart;
}
//helper method used above in separate static class
public static IEnumerable<T> ChildElements<T>(this OpenXmlElement el) where T: OpenXmlElement
{
if (el.HasChildren)
{
var child = el.GetFirstChild<T>();
while (child != null)
{
yield return child;
child = child.NextSibling<T>();
}
}
}
the out parameter placeholderShapes is assuming after creating a new slide based on a master template that the developer will wish to alter some of the placeholder content
I think you should leave out the foreach loop that copies the image parts.
When I normally copy slides from a slidemaster I use a similar code setup that you are using, but without the foreach.
It then copies the given slide from the slidemaster part including all images, layout, etc.
The code I use in one of my projects is listed below (the SetTitle(string) call is to an external method, and I'm using a hard-coded position in the SlideMasterPart as opposed to your string based layout name.
public static void InsertNewSlideB(PresentationDocument presentationDocument, int position, string slideTitle)
{
if (presentationDocument == null)
{
throw new ArgumentNullException("presentationDocument");
}
if (slideTitle == null)
{
throw new ArgumentNullException("slideTitle");
}
PresentationPart presentationPart = presentationDocument.PresentationPart;
// Verify that the presentation is not empty.
if (presentationPart == null)
{
throw new InvalidOperationException("The presentation document is empty.");
}
// Declare and instantiate a new slide.
Slide slide = new Slide(new CommonSlideData(new ShapeTree()));
SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
slide.Save(slidePart);
SlideLayoutPart layoutPart = presentationPart.SlideMasterParts.ElementAt(0).SlideLayoutParts.ElementAt(1);
slidePart.AddPart<SlideLayoutPart>(layoutPart);
slidePart.Slide.CommonSlideData = (CommonSlideData)layoutPart.SlideLayout.CommonSlideData.Clone();
SetTitle(slidePart, slideTitle);
SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;
// Find the highest slide ID in the current list.
uint maxSlideId = 1;
SlideId prevSlideId = null;
foreach (SlideId slideId in slideIdList.ChildElements)
{
if (slideId.Id > maxSlideId)
{
maxSlideId = slideId.Id;
}
position--;
if (position == 0)
{
prevSlideId = slideId;
}
}
maxSlideId++;
// Insert the new slide into the slide list after the previous slide.
SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
newSlideId.Id = maxSlideId;
newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);
// Save the modified presentation.
presentationPart.Presentation.Save();
}

Draw Polygon in Googlemap based marker time

I want to draw a polygon by connecting markers in googlemap.Time is associated with each marker.So i want connect each points based on the time.How can i do this.Currently code is impleneted like this.Where i need to change.
var marker = new Array();
var points = new Array();
for(var i=0;i<value.length;i++)
{
var tempar=value[i].split(',');
var center = new GLatLng(tempar[0], tempar[1]);
var mar = new GMarker(center, icon);
var imgpth=tempar[3];
var tme=tempar[2];
marker.push(mar);
marker[i].time = tempar[2];
points.push(marker[i].getLatLng());
drawMarker(mar,imgpth,tme);
}
for(i=;i<marker.length;i++)
{
map.addOverlay(marker[i]);
}
var polyline = new GPolygon(points, "#f33f00", 2, 1, "#ff0000", 0.2);
map.addOverlay(polyline);
The easiest way to do this is to sort marker array by time. Assuming that the time property has some sensible values (not strings):
marker.sort(function(a,b){return a.time-b.time});
If the time is a string then:
marker.sort(function(a,b) {
var date1 = new Date(a.time);
var date2 = new Date(b.time);
return date1.getTime() - date2.getTime();
});

Categories