IfcOpenShell(Parse)_IFC PropertySet, printing issue - parsing

Hy, I am new to programming and I have problems with printing my property sets and values.
I have more elements in my IFC and want to Parse all Property Sets and values.
My current result is elements ID(for every element), but it takes the attributes(property sets and values) form the first one.
Sketch:
see image
My code:
import ifcopenshell
ifc_file = ifcopenshell.open('D:\PZI_9-1_1441_LIN_CES_1-17c-O_M-M3.ifc')
products = ifc_file.by_type('IFCPROPERTYSET')
for product in products:
print(product.is_a())
print(product) # Prints
Category_Name_1 = ifc_file.by_type('IFCBUILDINGELEMENTPROXY')[0]
for definition in Category_Name_1.IsDefinedBy:
property_set = definition.RelatingPropertyDefinition
headders_list = []
data_list = []
max_len = 0
for property in property_set.HasProperties:
if property.is_a('IfcPropertySingleValue'):
headers = (property.Name)
data= (property.NominalValue.wrappedValue)
#print(headders)
headders_list.append(headers)
if len(headers) > max_len: max_len = len(headers)
#print(data)
data_list.append(data)
if len(data) > max_len: max_len = len(data)
headders_list = [headers.ljust(max_len) for headers in headders_list]
data_list = [data.ljust(max_len) for data in data_list]
print(" ".join(headders_list))
print(" ".join(data_list))
Has somebody a solution?
Thanks and kind regards,

On line:
Category_Name_1 = ifc_file.by_type('IFCBUILDINGELEMENTPROXY')[0]
it seems that you are referring always to the first IfcBuildingElementProxy object (because of the 0-index). The index should be incremented for each product, I guess.

Related

Select particular listbox value on start of Dynpro?

I have a custom dialog dynpro including an input field named DYN_MATNR as listbox for which I have included a list of particular materials as selection.
How can I set a specific material (of that list) as selected when the dialog dynpro is opened?
PBO of dialog dynpro:
data lt_values type vrm_values.
select matnr,
maktx
into table #data(lt_materials)
from makt
where matnr in #so_matnr
and spras = 'D'
order by matnr.
loop at lt_materials assigning field-symbol(<material>).
append initial line to lt_values assigning field-symbol(<value>).
<value>-key = <material>-matnr.
<value>-text = <material>-maktx.
endloop.
call function 'VRM_SET_VALUES'
exporting
id = 'DYN_MATNR'
values = lt_values
exceptions
id_illegal_name = 1
others = 2.
if sy-subrc <> 0.
" ...
endif.
This works and it shows the list of materials as listbox values. To select a particular material I have included the FM DYNP_VALUES_UPDATE afterwards and also in PBO but this did not work:
data lv_stepl type syst-stepl.
call function 'DYNP_GET_STEPL'
importing
povstepl = lv_stepl
exceptions
stepl_not_found = 1
others = 2.
if sy-subrc <> 0.
" ...
endif.
data(lt_dynpfields) = value dynpread_tabtype(
( fieldname = 'DYN_MATNR'
stepl = lv_stepl
fieldvalue = gcl_helper->get_matnr( ) " matnr which should be selected is stored here
fieldinp = space )
).
call function 'DYNP_VALUES_UPDATE'
exporting
dyname = sy-repid
dynumb = sy-dynnr
tables
dynpfields = lt_dynpfields
exceptions
invalid_abapworkarea = 1
invalid_dynprofield = 2
invalid_dynproname = 3
invalid_dynpronummer = 4
invalid_request = 5
no_fielddescription = 6
undefind_error = 7
others = 8.
if sy-subrc <> 0.
" ...
endif.
I am also not able to directly set DYN_MATNR as it is not available in PBO.
Any hints?
Got it:
You need to additionally define a global(!) variable with the name and (wished) type of the input field (e.g. in the top include of the report or in a separate include of the dynpro logic):
data dyn_matnr type matnr.
Then you can set the initial value of the dynpro field in PBO directly:
dyn_matnr = gcl_helper->get_matnr( ).
As this becomes rather irritating when using various dialog dynpros I recommend including the dynpro number in those variables and input fields.

Access any structure field chosen dynamically at run time

I have a problem, so I have a huge table where some fields contain only numbers from 1-20 and I want to move the values of the fields to a new table where there are 3 fields with a name and the number (zjdc01 or zadc01).
Now I want to check the field value from the huge table and append the values to the new fields.
For Example :
CASE LS_ATLAS_DC-ZJDC01.
WHEN 1.
LS_ATLAS-ZJDC01 = LS_ATLAS_DC-ZJDC01.
LS_ATLAS-ZADC01 = LS_ATLAS_DC-ZADC01.
LS_ATLAS-ZBDC01 = LS_ATLAS_DC-ZBDC01.
WHEN 2.
LS_ATLAS-ZJDC02 = LS_ATLAS_DC-ZJDC01.
LS_ATLAS-ZADC02 = LS_ATLAS_DC-ZADC01.
LS_ATLAS-ZBDC02 = LS_ATLAS_DC-ZBDC01.
WHEN 3.
LS_ATLAS-ZJDC03 = LS_ATLAS_DC-ZJDC01.
LS_ATLAS-ZADC03 = LS_ATLAS_DC-ZADC01.
LS_ATLAS-ZBDC03 = LS_ATLAS_DC-ZBDC01.
WHEN 4.
LS_ATLAS-ZJDC04 = LS_ATLAS_DC-ZJDC01.
LS_ATLAS-ZADC04 = LS_ATLAS_DC-ZADC01.
LS_ATLAS-ZBDC04 = LS_ATLAS_DC-ZBDC01.
But this is very exhausting and I think there is another Solution but I dont know if ABAP have something for this.
Maybe some of you have a Solution or have a similiar problem which he solved.
Use ASSIGN COMPONENT name OF STRUCTURE structure TO <field_symbol>.
DATA name TYPE string. " component name
FIELD-SYMBOLS: <zjdc_xx> TYPE any,
<zadc_xx> TYPE any,
<zbdc_xx> TYPE any.
IF number BETWEEN 1 and 4.
name = |ZJDC{ number WIDTH = 2 ALIGN = RIGHT PAD = '0' }|. "<== ZJDC01 to ZJDC04
ASSIGN COMPONENT name OF STRUCTURE ls_atlas TO <zjdc_xx>.
name = |ZADC{ number WIDTH = 2 ALIGN = RIGHT PAD = '0' }|. "<== ZADC01 to ZADC04
ASSIGN COMPONENT name OF STRUCTURE ls_atlas TO <zadc_xx>.
name = |ZBDC{ number WIDTH = 2 ALIGN = RIGHT PAD = '0' }|. "<== ZBDC01 to ZBDC04
ASSIGN COMPONENT name OF STRUCTURE ls_atlas TO <zbdc_xx>.
<zjdc_xx> = LS_ATLAS_DC-ZJDC01.
<zadc_xx> = LS_ATLAS_DC-ZADC01.
<zbdc_xx> = LS_ATLAS_DC-ZBDC01.
ENDIF.

How to parse the config file shown to create a lua table that is desired?

I want to parse a config file which has information like:
[MY_WINDOW_0]
Address = 0xA0B0C0D0
Size = 0x100
Type = cpu0
[MY_WINDOW_1]
Address = 0xB0C0D0A0
Size = 0x200
Type = cpu0
[MY_WINDOW_2]
Address = 0xC0D0A0B0
Size = 0x100
Type = cpu1
into a LUA table as follows
CPU_TRACE_WINDOWS =
{
["cpu0"] = {{address = 0xA0B0C0D0, size = 0x100},{address = 0xB0C0D0A0, size = 0x200},}
["cpu1"] = {{address = 0xC0D0A0B0, size = 0x100},...}
}
I tried my best with some basic LUA string manipulation functions but couldn't get the output that I'm looking for due to repetition of strings in each sections like 'Address',' Size', 'Type' etc. Also my actual config file is huge with 20 such sections.
I got so far, this is basically one section of the code, rest would be just repetition of the logic.
OriginalConfigFile = "test.cfg"
os.execute("cls")
CPU_TRACE_WINDOWS = {}
local bus
for line in io.lines(OriginalConfigFile) do
if string.find(line, "Type") ~= nil then
bus = string.gsub(line, "%a=%a", "")
k,v = string.match(bus, "(%w+) = (%w+)")
table.insert(CPU_TRACE_WINDOWS, v)
end
end
Basically I'm having trouble with coming up with the FINAL TABLE STRUCTURE that I need. v here is the different rvalues of the string "Type". I'm having issues with arranging it in the table. I'm currently working to find a solution but I thought I could ask for help meanwhile.
This should work for you. Just change the filename to wherever you have your config file stored.
f, Address, Size, Type = io.input("configfile"), "", "", ""
CPU_TRACE_WINDOWS = {}
for line in f:lines() do
if line:find("MY_WINDOW") then
Type = ""
Address = ""
Size = ""
elseif line:find("=") then
_G[line:match("^%a+")] = line:match("[%d%a]+$")
if line:match("Type") then
if not CPU_TRACE_WINDOWS[Type] then
CPU_TRACE_WINDOWS[Type] = {}
end
table.insert(CPU_TRACE_WINDOWS[Type], {address = Address, size = Size})
end
end
end
end
It searches for the MY_WINDOW phrase and resets the variable. If the table exists within CPU_TRACE_WINDOWS, then it just appends a new table value, otherwise it just creates it. Note that this is dependent upon Type always being the last entry. If it switches up anywhere, then it will not have all the required information. There may be a cleaner way to do it, but this works (tested on my end).
Edit: Whoops, forgot to change the variables in the middle there if MY_WINDOW matched. That needed to be corrected.
Edit 2: Cleaned up the redundancy with table.insert. Only need it once, just need to make sure the table is created first.

Calculate no of attachments and show it in tree view in openerp 7.0

I am using the following code to add a new column in stock.picking.in object and update the no of attachments to it (to show in tree view the count of attachments).
class stock_picking(osv.osv):
_inherit = "stock.picking.in"
_name = 'stock.picking.in'
def count_attachments(self, cr, uid, ids, fields, arg, context):
obj_attachment = self.pool.get('ir.attachment')
for record in self:
_logger.info("record now in tree view:"+record)
record.attachment_count =0
attachment_ids = obj_attachment.search([('res_model','=','stock.picking.in'),('res_id','=',record.id)]).ids
if attachment_ids:
record.attachment_count =len(attachment_ids)
return record
_columns = {
'attachment_count' :fields.function(count_attachments,method=True,string="Attachment Count" ,type='integer')
}
stock_picking()
Then I have added the following line to the tree view.
<field name="attachment_count">
to show the count in tree view.
However the values are not getting updated and the count_attachments is not getting called.
Any help is appreciated. Thanks in advance!
Try following,
class stock_picking(osv.osv):
_inherit = "stock.picking.in"
_name = 'stock.picking.in'
def count_attachments(self, cr, uid, ids, fields, arg, context=None):
obj_attachment = self.pool.get('ir.attachment')
res = {}
for record in self:
res[record.id] = 0
_logger.info("record now in tree view:"+record)
attachment_ids = obj_attachment.search([('res_model','=','stock.picking.in'),('res_id','=',record.id)]).ids
if attachment_ids:
res[record.id] = len(attachment_ids)
return res
_columns = {
'attachment_count' :fields.function(count_attachments,method=True,string="Attachment Count" ,type='integer')
}

Randomly select a key from a table in Lua

I want to randomly populate a grid in Lua using a list of possible items, which is defined as follows:
-- Items
items = {}
items.glass = {}
items.glass.color = colors.blue
items.brick = {}
items.brick.color = colors.red
items.grass = {}
items.grass.color = colors.green
So the keys of the table are "glass", "brick" and "grass".
How do I randomly select one of these keys if they are not addressable by a numeric index?
Well, I kind of got a workaround, but I would be open to any better suggestions.
The first solution consists of having a secondary table which serves as an index to the first table:
item_index = {"grass", "brick", "glass"}
Then I can randomly store a key of this table (board is a matrix that stores the value of the random entry in item_index):
local index = math.random(1,3)
board[i][j] = item_index[index]
After which I can get details of the original list as follows:
items[board[y][x]].color
The second solution, which I have decided on, involves adding the defined elements as array elements to the original table:
-- Items
items = {}
items.glass = {}
items.glass.color = colors.blue
table.insert(items, items.glass) --- Add item as array item
items.brick = {}
items.brick.color = colors.red
table.insert(items, items.brick) --- Add item as array item
items.grass = {}
items.grass.color = colors.green
table.insert(items, items.grass) --- Add item as array item
Then, I can address the elements directly using an index:
local index = math.random(1,3)
board[i][j] = items[index]
And they can be retrieved directly without the need for an additional lookup:
board[y][x].color
Although your second method gives concise syntax, I think the first is easier to maintain. I can't test here, but I think you can get the best of both, won't this work:
local items = {
glass = {
color = colors.blue,
},
brick = {
color = colors.red,
},
grass = {
color = colors.green,
},
}
local item_index = {"grass", "brick", "glass"}
local index = math.random(1,3)
board[i][j] = items[item_index[index]]
print('color:', board[i][j].color)
If you're table is not too big and you can just break off at a random point. This method assumes that you know the number of entries in the table (which is not equal to #table value, if the table has non-number keys).
So find the length of the table, then break at random(1, length(table)), like so:
local items = {} ....
items.grass.color = colors.green
local numitems = 0 -- find the size of the table
for k,v in pairs(items) do
numitems = numitems + 1
end
local randval = math.random(1, numitems) -- get a random point
local randentry
local count = 0
for k,v in pairs(items) do
count = count + 1
if(count == randentry) then
randentry = {key = k, val = v}
break
end
end
The goods: You don't have to keep track of the keys. It can be any table, you don't need to maintain it.
The bad and ugly: It is O(n) - two linear passes.So, it is not at all ideal if you have big table.
The above answers assume you know what all of the keys are, which isn't something I was able to do earlier today. My solution:
function table.randFrom( t )
local choice = "F"
local n = 0
for i, o in pairs(t) do
n = n + 1
if math.random() < (1/n) then
choice = o
end
end
return choice
end
Explanation: we can't use table.getn( t ) to get the size of the table, so we track it as we go. The first item will have a 1/1=1 chance of being picked; the second 1/2 = 0.5, and so on...
If you expand for N items, the Nth item will have a 1/N chance of being chosen. The first item will have a 1 - (1/2) - (1/3) - (1/4) - ... - (1/N) chance of not being replaced (remember, it is always chosen at first). This series converges to 1 - (N-1)/N = 1/N, which is equal to the chance of the last item being chosen.
Thus, each item in the array has an equal likelihood of being chosen; it is uniformly random. This also runs in O(n) time, which isn't great but it's the best you can do if you don't know your index names.

Resources