How to I extract only the lowest-level objects in Xbim? - c#

I have a BIM model in IFC format and I want to add a new property, say cost, to every object in the model using Xbim. I am building a .NET application. The following code works well, except, the property is also added to storeys, buildings and sites - and I only want to add it to the lowest-level objects that nest no other objects.
To begin with, I have tried various methods to print the "related objects" of each object, thinking that I could filter out any objects with non-null related objects. This has led me to look at this:
IfcRelDefinesByType.RelatedObjects (http://docs.xbim.net/XbimDocs/html/7fb93e55-dcf7-f6da-0e08-f8b5a70accf2.htm) from thinking that RelatedObjects (https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/FINAL/HTML/ifckernel/lexical/ifcreldecomposes.htm) would contain this information.
But I have not managed to implement working code from this documentation.
Here is my code:
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Xbim.Ifc;
using Xbim.Ifc2x3.Interfaces;
using Xbim.Ifc4.Kernel;
using Xbim.Ifc4.MeasureResource;
using Xbim.Ifc4.PropertyResource;
using Xbim.Ifc4.Interfaces;
using IIfcProject = Xbim.Ifc4.Interfaces.IIfcProject;
namespace MyPlugin0._1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
outputBox.AppendText("Plugin launched successfully");
}
private void button1_Click(object sender, EventArgs e)
{
// Setup the editor
var editor = new XbimEditorCredentials
{
ApplicationDevelopersName = "O",
ApplicationFullName = "MyPlugin",
ApplicationIdentifier = "99990100",
ApplicationVersion = "0.1",
EditorsFamilyName = "B",
EditorsGivenName = "O",
EditorsOrganisationName = "MyWorkplace"
};
// Choose an IFC file to work with
OpenFileDialog dialog = new OpenFileDialog();
dialog.ShowDialog();
string filename = dialog.FileName;
string newLine = Environment.NewLine;
// Check if the file is valid and continue
if (!filename.ToLower().EndsWith(".ifc"))
{
// Output error if the file is the wrong format
outputBox.AppendText(newLine + "Error: select an .ifc-file");
}
else
{
// Open the selected file (## Not sure what the response is to a corrupt/invalid .ifc-file)
using (var model = IfcStore.Open(filename, editor, 1.0))
{
// Output success when the file has been opened
string reversedName = Form1.ReversedString(filename);
int filenameShortLength = reversedName.IndexOf("\\");
string filenameShort = filename.Substring(filename.Length - filenameShortLength, filenameShortLength);
outputBox.AppendText(newLine + filenameShort + " opened successfully for editing");
////////////////////////////////////////////////////////////////////
// Get all the objects in the model ( ### lowest level only??? ###)
var objs = model.Instances.OfType<IfcObjectDefinition>();
////////////////////////////////////////////////////////////////////
// Create and store a new property
using (var txn = model.BeginTransaction("Store Costs"))
{
// Iterate over all the walls to initiate the Point Source property
foreach (var obj in objs)
{
// Create new property set to host properties
var pSetRel = model.Instances.New<IfcRelDefinesByProperties>(r =>
{
r.GlobalId = Guid.NewGuid();
r.RelatingPropertyDefinition = model.Instances.New<IfcPropertySet>(pSet =>
{
pSet.Name = "Economy";
pSet.HasProperties.Add(model.Instances.New<IfcPropertySingleValue>(p =>
{
p.Name = "Cost";
p.NominalValue = new IfcMonetaryMeasure(200.00); // Default Currency set on IfcProject
}));
});
});
// Add property to the object
pSetRel.RelatedObjects.Add(obj);
// Rename the object
outputBox.AppendText(newLine + "Cost property added to " + obj.Name);
obj.Name += "_withCost";
//outputBox.AppendText(newLine + obj.OwnerHistory.ToString());
}
// Commit changes to this model
txn.Commit();
};
// Save the changed model with a new name. Does not overwrite existing files but generates a unique name
string newFilename = filenameShort.Substring(0, filenameShort.Length - 4) + "_Modified.IFC";
int i = 1;
while (File.Exists(newFilename))
{
newFilename = filenameShort.Substring(0, filenameShort.Length - 4) + "_Modified(" + i.ToString() + ").IFC";
i += 1;
}
model.SaveAs(newFilename); // (!) Gets stored in the project folder > bin > Debug
outputBox.AppendText(newLine + newFilename + " has been saved");
};
}
}
// Reverse string-function
static string ReversedString(string text)
{
if (text == null) return null;
char[] array = text.ToCharArray();
Array.Reverse(array);
return new String(array);
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}

You're starting out by getting too broad a set of elements in the model. Pretty much everything in an IFC model will be classed as (or 'derived from') an instance of IfcObjectDefinition - including Spatial concepts (spaces, levels, zones etc) as well as more abstract concepts of Actors (people), Resources and the like.
You'd be better off filtering down objs to the more specific types such as IfcElement, IfcBuildingElement - or even the more real world elements below (IfcWindow, IfcDoor etc.)
// Get all the building elements in the model
var objs = model.Instances.OfType<IfcBuildingElement>();
You could also filter by more specific clauses more than just their type by using the other IFC relationships.

Related

Methods return type in C#

i am using a method to retrieve data from an OPC DA server using TitaniumAS packages, the problem i am having is that i have a lot of tags to read/write so i have to use methods.
The WriteX method works fines as it doesnt have to return anything but the read does not, well it does its job, it reads but i cannot use that data outside of the method because it was a void method, when i tried to use it as a String method (that's the type of data i need) it says :
Error CS0161 'ReadX(string, string)': not all code paths return a value
PS : note that i am just a beginner in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TitaniumAS.Opc.Client.Common;
using TitaniumAS.Opc.Client.Da;
using TitaniumAS.Opc.Client.Da.Browsing;
using System.Threading;
using System.Threading.Channels;
using Async;
namespace OPCDA
{
class Program
{
static void Main(string[] args)
{
TitaniumAS.Opc.Client.Bootstrap.Initialize();
Uri url = UrlBuilder.Build("Kepware.KEPServerEX.V6");
using (var server = new OpcDaServer(url))
{
server.Connect();
OpcDaGroup group = server.AddGroup("MyGroup");
group.IsActive = true;
Ascon ascon1 = new Ascon();
ReadX("Channel1.Ascon1.AsconS", ascon1.ALM);
Console.WriteLine("value = {0}", ascon1.ALM);
void WriteX(String Link, String Ascon)
{
var definition1 = new OpcDaItemDefinition
{
ItemId = Link,
IsActive = true
};
OpcDaItemDefinition[] definitions = { definition1 };
OpcDaItemResult[] results = group.AddItems(definitions);
OpcDaItem tag = group.Items.FirstOrDefault(i => i.ItemId == Link);
OpcDaItem[] items = { tag };
object[] Values = { Ascon };
HRESULT[] Results = group.Write(items, Values);
}
string ReadX(String Link, String read)
{
var definition1 = new OpcDaItemDefinition
{
ItemId = Link,
IsActive = true
};
OpcDaItemDefinition[] definitions = { definition1 };
OpcDaItemResult[] results = group.AddItems(definitions);
OpcDaItemValue[] values = group.Read(group.Items, OpcDaDataSource.Device);
read = Convert.ToString(values[0].Value);
}
}
}
}
}
the first step was to state the return like this :
return Convert.ToString(values[0].Value) instead of read = Convert.ToString(values[0].Value)
then go up and use that value with my variable :
ascon1.ALM=ReadX("Channel1.Ascon1.AsconS");

import Csv file Oledb C#

Hi please can anyone give me solution to this problem,i have to import csv file using c# but i have this problem in this screenshot
Screen
the separate betwenn column is ',' but in the data there is a rows tha contains ".
Mohamed, I cannot see your screenshot, but can point you toward generic lists and creating a class to represent data. You will need to add references from the "Project" menu.
Microsoft.VisualBasic
System.Configuration
WindowsBase
I am including code from a snippet of code where I was doing that:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualBasic.FileIO;
namespace CsvToListExp
{
class Program
{
public static void Main(string[] args)
{
// HARD_CODED FOR EXAMPLE ONLY - TO BE RETRIEVED FROM APP.CONFIG IN REAL PROGRAM
string hospPath = #"C:\\events\\inbound\\OBLEN_COB_Active_Inv_Advi_Daily_.csv";
string vendPath = #"C:\\events\\outbound\\Advi_OBlen_Active_Inv_Ack_Daily_.csv";
List<DenialRecord> hospList = new List<DenialRecord>();
List<DenialRecord> vendList = new List<DenialRecord>();
//List<DenialRecord> hospExcpt = new List<DenialRecord>(); // Created at point of use for now
//List<DenialRecord> vendExcpt = new List<DenialRecord>(); // Created at point of use for now
using (TextFieldParser hospParser = new Microsoft.VisualBasic.FileIO.TextFieldParser(hospPath))
{
hospParser.TextFieldType = FieldType.Delimited;
hospParser.SetDelimiters(",");
hospParser.HasFieldsEnclosedInQuotes = false;
hospParser.TrimWhiteSpace = true;
while (!hospParser.EndOfData)
{
try
{
string[] row = hospParser.ReadFields();
if (row.Length <= 7)
{
DenialRecord dr = new DenialRecord(row[0], row[1], row[2], row[3], row[4], row[5], row[6]);
hospList.Add(dr);
}
}
catch (Exception e)
{
// do something
Console.WriteLine("Error is: {0}", e.ToString());
}
}
hospParser.Close();
hospParser.Dispose();
}
using (TextFieldParser vendParser = new Microsoft.VisualBasic.FileIO.TextFieldParser(vendPath))
{
vendParser.TextFieldType = FieldType.Delimited;
vendParser.SetDelimiters(",");
vendParser.HasFieldsEnclosedInQuotes = false;
vendParser.TrimWhiteSpace = true;
while (!vendParser.EndOfData)
{
try
{
string[] row = vendParser.ReadFields();
if (row.Length <= 7)
{
DenialRecord dr = new DenialRecord(row[0], row[1], row[2], row[3], row[4], row[5], row[6]);
vendList.Add(dr);
}
}
catch (Exception e)
{
// do something
Console.WriteLine("Error is: {0}", e.ToString());
}
}
vendParser.Close();
vendParser.Dispose();
}
// Compare the lists each way for denials not in the other source
List<DenialRecord> hospExcpt = hospList.Except(vendList).ToList();
List<DenialRecord> vendExcpt = vendList.Except(hospList).ToList();
}
}
}
Google TestFieldParser and look at the methods, properties and constructors. It is very versatile, but runs slowly due to the layers it goes through. It has the ability to set the delimiter, handle fields wrapped in quotes, trim whitespace and many more.

How to create an array and fill from tree node variable

I'm trying to transfer data from a treenode (at least I think that's what it is) which contains much more data than I need. It would be very difficult for me to manipulate the data within the treenode. I would much rather have an array which provides me with only the necessary data for data manipulation.
I would like higher rates have following variables:
1. BookmarkNumber (integer)
2. Date (string)
3. DocumentType (string)
4. BookmarkPageNumberString (string)
5. BookmarkPageNumberInteger (integer)
I would like to the above defined rate from the data from variable book_mark (as can be seen in my code).
I've been wrestling with this for two days. Any help would be much appreciated. I'm probably sure that the question wasn't phrased correctly so please ask questions so that I may explain further if needed.
Thanks so much
BTW what I'm trying to do is create a Windows Form program which parses a PDF file which has multiple bookmarks into discrete PDF files for each bookmark/chapter while saving the bookmark in the correct folder with the correct naming convention, the folder and naming convention dependent upon the PDF name and title name of the bookmark/chapter being parsed.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using itextsharp.pdfa;
using iTextSharp.awt;
using iTextSharp.testutils;
using iTextSharp.text;
using iTextSharp.xmp;
using iTextSharp.xtra;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void ChooseImageFileWrapper_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = GlobalVariables.InitialDirectory;
openFileDialog1.Filter = "Pdf Files|*.pdf";
openFileDialog1.RestoreDirectory = true;
openFileDialog1.Title = "Image File Wrapper Chooser";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
GlobalVariables.ImageFileWrapperPath = openFileDialog1.FileName;
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
ImageFileWrapperPath.Text = GlobalVariables.ImageFileWrapperPath;
}
private void ImageFileWrapperPath_TextChanged(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
iTextSharp.text.pdf.PdfReader pdfReader = new iTextSharp.text.pdf.PdfReader(GlobalVariables.ImageFileWrapperPath);
IList<Dictionary<string, object>> book_mark = iTextSharp.text.pdf.SimpleBookmark.GetBookmark(pdfReader);
List<ImageFileWrapperBookmarks> IFWBookmarks = new List<ImageFileWrapperBookmarks>();
foreach (Dictionary<string, object> bk in book_mark) // bk is a single instance of book_mark
{
ImageFileWrapperBookmarks.BookmarkNumber = ImageFileWrapperBookmarks.BookmarkNumber + 1;
foreach (KeyValuePair<string, object> kvr in bk) // kvr is the key/value in bk
{
if (kvr.Key == "Kids" || kvr.Key == "kids")
{
//create recursive program for children
}
else if (kvr.Key == "Title" || kvr.Key == "title")
{
}
else if (kvr.Key == "Page" || kvr.Key == "page")
{
}
}
}
MessageBox.Show(GlobalVariables.ImageFileWrapperPath);
}
}
}
Here's one way to parse a PDF and create a data structure similar to what you describe. First the data structure:
public class BookMark
{
static int _number;
public BookMark() { Number = ++_number; }
public int Number { get; private set; }
public string Title { get; set; }
public string PageNumberString { get; set; }
public int PageNumberInteger { get; set; }
public static void ResetNumber() { _number = 0; }
// bookmarks title may have illegal filename character(s)
public string GetFileName()
{
var fileTitle = Regex.Replace(
Regex.Replace(Title, #"\s+", "-"),
#"[^-\w]", ""
);
return string.Format("{0:D4}-{1}.pdf", Number, fileTitle);
}
}
A method to create a list of Bookmark (above):
List<BookMark> ParseBookMarks(IList<Dictionary<string, object>> bookmarks)
{
int page;
var result = new List<BookMark>();
foreach (var bookmark in bookmarks)
{
// add top-level bookmarks
var stringPage = bookmark["Page"].ToString();
if (Int32.TryParse(stringPage.Split()[0], out page))
{
result.Add(new BookMark() {
Title = bookmark["Title"].ToString(),
PageNumberString = stringPage,
PageNumberInteger = page
});
}
// recurse
if (bookmark.ContainsKey("Kids"))
{
var kids = bookmark["Kids"] as IList<Dictionary<string, object>>;
if (kids != null && kids.Count > 0)
{
result.AddRange(ParseBookMarks(kids));
}
}
}
return result;
}
Call method above like this to dump the results to a text file:
void DumpResults(string path)
{
using (var reader = new PdfReader(path))
{
// need this call to parse page numbers
reader.ConsolidateNamedDestinations();
var bookmarks = ParseBookMarks(SimpleBookmark.GetBookmark(reader));
var sb = new StringBuilder();
foreach (var bookmark in bookmarks)
{
sb.AppendLine(string.Format(
"{0, -4}{1, -100}{2, -25}{3}",
bookmark.Number, bookmark.Title,
bookmark.PageNumberString, bookmark.PageNumberInteger
));
}
File.WriteAllText(outputTextFile, sb.ToString());
}
}
The bigger problem is how to extract each Bookmark into a separate file. If every Bookmark starts a new page it's easy:
Iterate over the return value of ParseBookMarks()
Select a page range that begins with the current BookMark.Number, and ends with the next BookMark.Number - 1
Use that page range to create separate files.
Something like this:
void ProcessPdf(string path)
{
using (var reader = new PdfReader(path))
{
// need this call to parse page numbers
reader.ConsolidateNamedDestinations();
var bookmarks = ParseBookMarks(SimpleBookmark.GetBookmark(reader));
for (int i = 0; i < bookmarks.Count; ++i)
{
int page = bookmarks[i].PageNumberInteger;
int nextPage = i + 1 < bookmarks.Count
// if not top of page will be missing content
? bookmarks[i + 1].PageNumberInteger - 1
/* alternative is to potentially add redundant content:
? bookmarks[i + 1].PageNumberInteger
*/
: reader.NumberOfPages;
string range = string.Format("{0}-{1}", page, nextPage);
// DEMO!
if (i < 10)
{
var outputPath = Path.Combine(OUTPUT_DIR, bookmarks[i].GetFileName());
using (var readerCopy = new PdfReader(reader))
{
var number = bookmarks[i].Number;
readerCopy.SelectPages(range);
using (FileStream stream = new FileStream(outputPath, FileMode.Create))
{
using (var document = new Document())
{
using (var copy = new PdfCopy(document, stream))
{
document.Open();
int n = readerCopy.NumberOfPages;
for (int j = 0; j < n; )
{
copy.AddPage(copy.GetImportedPage(readerCopy, ++j));
}
}
}
}
}
}
}
}
}
The problem is that it's highly unlikely all bookmarks are going to be at the top of every page of the PDF. To see what I mean, experiment with commenting / uncommenting the bookmarks[i + 1].PageNumberInteger lines.

RallyDev - Getting Tasks for Stories using Rally.RestAPI.dll and Service V2.0

I'm pulling data off the Rally server at https://rally1.rallydev.com using C# and the Rally.RestAPI.dll. The server was recently upgraded to webservice v2.0 and I'm having some problems getting tasks for a user story. I know the way child collections are presented were changed in the API with the move to 2.0, but what I'm trying isn't working.
v2.0 removed the ability to return child collections in the same
response for performance reasons. Now fetching a collection will return
an object with the count and the url from which to get the collection
data.A separate request is needed to get to the elements of the
collection.
Here is the code that iterates over user story results, accesses "Tasks" collection on stories and issues a separate request to access individual Task attributes:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using Rally.RestApi;
using Rally.RestApi.Response;
namespace aRestApp_CollectionOfTasks
{
class Program
{
static void Main(string[] args)
{
//Initialize the REST API
RallyRestApi restApi;
restApi = new RallyRestApi("user#co.com", "secret", "https://rally1.rallydev.com", "v2.0");
//Set our Workspace and Project scopings
String workspaceRef = "/workspace/11111"; //please replace this OID with an OID of your workspace
String projectRef = "/project/22222"; //please replace this OID with an OID of your project
bool projectScopingUp = false;
bool projectScopingDown = true;
Request storyRequest = new Request("HierarchicalRequirement");
storyRequest.Workspace = workspaceRef;
storyRequest.Project = projectRef;
storyRequest.ProjectScopeUp = projectScopingUp;
storyRequest.ProjectScopeDown = projectScopingDown;
storyRequest.Fetch = new List<string>()
{
"Name",
"FormattedID",
"Tasks",
"Estimate"
};
storyRequest.Query = new Query("LastUpdateDate", Query.Operator.GreaterThan, "2013-08-01");
QueryResult queryStoryResults = restApi.Query(storyRequest);
foreach (var s in queryStoryResults.Results)
{
Console.WriteLine("----------");
Console.WriteLine("FormattedID: " + s["FormattedID"] + " Name: " + s["Name"]);
//Console.WriteLine("Tasks ref: " + s["Tasks"]._ref);
Request taskRequest = new Request(s["Tasks"]);
QueryResult queryTaskResult = restApi.Query(taskRequest);
if (queryTaskResult.TotalResultCount > 0)
{
foreach (var t in queryTaskResult.Results)
{
var taskEstimate = t["Estimate"];
var taskName = t["Name"];
Console.WriteLine("Task Name: " + taskName + " Estimate: " + taskEstimate);
}
}
else
{
Console.WriteLine("no tasks found");
}
}
}
}
}

How to use PrintCapabilities Class in C#

I am trying to intercept a printer job and change the attributes of the print job. I can intercept the print job and get information regarding it. I followed this article for that
http://www.codeproject.com/Questions/423178/printing-order-intercept-with-csharp
Now I want to change the paper size of the print job and for that I found this article
http://social.msdn.microsoft.com/Forums/en/windowsxps/thread/8af6ba92-5d2c-444b-91f4-a8747739c1b7
But the problem is I cannot create class PrintCapabilities. Am I missing something ?? Please help.
My current code looks like the following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Printing;
namespace PrintJob
{
class EvenWatch
{
private ManagementEventWatcher manEWatch;
public EvenWatch(string host)
{
System.Management.ManagementScope oMs = new System.Management
.ManagementScope(#"\\" + host + #"\root\cimv2");
oMs.Connect();
manEWatch = new ManagementEventWatcher(oMs, new EventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 0.1 WHERE TargetInstance ISA 'Win32_PrintJob'"));
manEWatch.EventArrived += new EventArrivedEventHandler(
mewPrintJobs_EventArrived);
manEWatch.Start();
}
static void mewPrintJobs_EventArrived(object sender, EventArrivedEventArgs e)
{
foreach (PropertyData prop in e.NewEvent.Properties)
{
string val = prop.Value == null ? "null" : prop.Value.ToString();
}
ManagementBaseObject printJob = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value;
string v = "";
foreach (PropertyData propp in printJob.Properties)
{
string name = propp.Name;
string val = propp.Value == null ? "null" : propp.Value.ToString();
val += "\n";
v += name + ":" + val;
}
PrintQueue printerSpooler = null;
printerSpooler = new PrintQueue(new PrintServer(), "EPSON LQ-300+ /II ESC/P 2");
PrintJobSettings printJobSetting = printerSpooler.CurrentJobSettings;
string desc = printJobSetting.Description;
//printerSpooler.CurrentJobSettings.CurrentPrintTicket
Console.WriteLine("-------");
Console.WriteLine(v);
}
}
}
I actually found out the answer. If you are using 4.0 you should also reference ReachFramework.dll once you do that the magic does happen :)

Categories

Resources