Story: How to create Bill of material - HiStructClient/femcad-doc GitHub Wiki

How to create bill of material

Bill of material (BOM) is surely one of the most needed output of structure configuration. So how to collect all the data that are already inputed in the code and make a nice summary out of them? In FemCad there is very useful collector of data from a particular class.

1. Start with model

First you define a model from which you want to collect data a make BOM. Add sufix .Fcm which serves as a pointer to particular class.

BomModel := SiloMainClass.Fcm

It can be either separate *.fcs file or some variable from the current *.fcs file. Basically a gclass (not gblock).

All the gblocks (active) in it are taken into account for data grabbing. This is very useful because you can turn on and off some gblocks by updaters.

Note: Althought it might be a good idea to use Fcm for sending information to another class, it is strongly recommended to do it exceptionally only. Apart from other reasons there is a danger of cyclic dependency.

2. Define buckets

For collection we need some root (which is the model above) where we collect data and bucket definition. Buckets are basically packages of items that are collected from the model based on particular common property.

ItemsCollection := Fcs.Assembly.Collector{				
                    Root := BomModel,
                BucketDefinitions := [
	            Fcs.Assembly.BucketDefinition{Name = "beams", ByClassTypeName = "SimpleBeamPartClass"},
	            Fcs.Assembly.BucketDefinition{Name = "purlins", ByClassTypeName = "PurlinAssy"},
	            Fcs.Assembly.BucketDefinition{Name = "lin", ByClassTypeName = "LinearTractionPart", ByFunction = bucket,fmi=>fmi.Fcm.PinColor==""gray""},
        	  ]

Each bucket has got Name (even though it is not used further, usually) and specification how to collect data - e.g. by class type name. (Note simple equal mark inside brackets.)

There are four possibilities how to define which data goes to bucket and they are evaluated in the following order...

ByNameMask
ByClassTypeName
ByHasProperty
ByFunction

If some item fulfills all the conditions (there can be more of them in BucketDefinition), it is put into the bucket.

It is recommended to think about how you need to collect items and which data you need afterwards. Do you need just length of beams? Then you can probably make a bucket of lines only. Do you need the end coordinates? Then you should collect simpleBeamsParts, for example. Do you need some special property? Then you collect by that property, etc.

3. Items are collected

Now the data are collected and we can easily print them, e.g.:

print ItemsCollection.Buckets[0].Items

We can also start counting them, e.g. for the second bucket...

ItemsCollection.Buckets[1].Items.Count

We may also need to collect items with identical property and sum them up, the code example is:

SummedItemsPerLength:= ItemsCOllection.CollectBy(i => i.Length)
.Buckets
.Select(bucket => 
	{name := bucket.Items[0].Name,
            sumLength := Round(bucket.Items.SumItems(i =>i.Length),3)}
	)
).OrderByDescendingMore([j => j.section.Name, j => j.length])

The last row also orders the list in two steps - first by names and then by lengths. It may be needed to keep much more information than just name and length, so that we can use it afterwards. Basically, any result needs to be calculated in advance because there is no possibility to do any summation in the table itself (see further steps).

4. Create report

Reporting entities in FemCad count various items, for example:

Fcs.Reporting.Document
Fcs.Reporting.Table
Fcs.Reporting.Text
Fcs.Reporting.Image

Complete list is presented in chapter E1. The first and foremost - Document - contains Title, DefaultSetup (is not edited the default one is used), Collapsed (True/False) and Children which is an array of various items.

Report1:= Fcs.Reporting.Document{
    Title := "The coolest title ever",
    DefaultSetup := res.doc.DocSetup.Standard{},
    Collapsed := False,
    Children :=[
	SomeText,
	SomePicture,
	SomeTable,
	]
}

Note: "Child" can be also another document. By using different Setup one can get identical document data but in another style.

Document can be displayed by command browse_report Report1 and is opened in default web browser.

Table is created using Header, Body and Footer. Not all of these three parts need to be defined. As already mentioned, data in the table must be calculated beforehead, no summation or other calculation is possible automatically. Header and Footer should contains one Fcs.Reporting.Table.Row, Bod can have as much rows as needed. Any row is defined via series of strings (number of strings defines the column count) or as an array. Example:

BomTable := Fcs.Reporting.Table{
    Header := Fcs.Reporting.Table.Row("Item", "Section", "Steel grade", "Length (mm)", "Quantity (pc)", "Volume (kg)"), 
    Body := res.f.EnumerableRange(beams.Count).Select(e => 
        Fcs.Reporting.Table.Row([
		Fcs.Reporting.Text((e+1).ToString()),
		Fcs.Reporting.Text(beams[e].section.Name),
		Fcs.Reporting.Text("S235"),
		Fcs.Reporting.Text((beams[e].length*1000).ToString()),
                    Fcs.Reporting.Text(beams[e].count),
		Fcs.Reporting.Text(beams[e].section.ch.EA*beams[e].sumLength*7850),
		])
	),
    Footer := Fcs.Reporting.Table.Row("Total sum", "", "", "", "", input.purlinsTotVolume.ToString("F1"))
    }	

5. Add pictures

There is a two step procedure how to define picture in document. The first one specifies image content as title. The syntax is, as mentioned in previous chapter:

Fcs.Reporting.Image{
    ImageContent := *see below*,
    Title := "What a beautiful title"}

The next one prescribes the ImageContent:

ImageContent := Fcs.Presentation.ImageRenderer{
    Model = Fcm,
    DrawSettingsFile=Fcm.GetFileNamePath("Report.fcsdrs"),
    ProjectionSettingsFile=Fcm.GetFileNamePath("Report.fcsdrv"),
    AutoZoom = True,
    }
  • Model - here you can choose the model to be depicted. If you type just Fcm it means the current class model. But you can define any other class (using updater for example) and make more images with a bit different content.
  • DrawSettingsFile - should posses the same name as current *.fcs file but with sufix *.fcs.drs, save in the same file folder. This file defines the drawing setup, for instance colours, turn on/off particular entities (vertexes, beams, tractions, ...) This file is to be save from FemCad. (e.g. right-mouse click on the screen).
  • ProjectionSettingsFile := should posses the same name as current *.fcs file but with sufix *.fcs.drv, save in the same file folder. This file defines the view setup, for example view direction, perspective on/off, image+text dpi, Picture size, ...) This file can be also save from FemCad. (e.g. right-mouse click on the screen).

Extras

E.1 Reporting items

The complete list of Fcs.Reporting items are the following:

public static Type Setup => typeof(ReportSetup);
public static Type Chapter => typeof(Chapter);
public static Type Document => typeof(Document);
public static Type Paragraph => typeof(Paragraph);
public static Type LocalizedText => typeof(LocalizedTextBlock);
public static Type Text => typeof(TextBlock);
public static Type Html => typeof(HtmlBlock);
public static Type Formula => typeof(FormulaBlock);
public static Type CascadingCheck => typeof(CascadingCheck);
public static Type CheckBlock => typeof(CheckBlock);
public static Type UnityCheckSection => typeof(UnityCheckSection);
public static Type Block => typeof(Block);
public static Type Table => typeof(TableBlock);
public static Type Symbol => typeof(SymbolBlock);
public static Type RenderWriter => typeof(RenderWriter);
public static Type TableOfContent => typeof(DocumentTableOfContent);
public static Type Image => typeof(ImageBlock);

E.2 Document setup

FCS.Reporting.Setup{
    LatexSyntax             := True/False,               # should remain True
    Units                   := unitSetup,                # independent units setup is possible for each document
    Collapsible             := True/False,
    GenerateTableOfContent  := True/False,
    Numbered                := True/False,
    ReportingIDsToReference := True/False }