import ast
import os
from os.path import abspath, isfile, join
import pexpect
import re
import sys
import traceback
import xml.etree.ElementTree as ET
import math
import uuid
TYPE_ARRAY = 'Array'
TYPE_DOUBLE = 'ScilabDouble'
TYPE_STRING = 'ScilabString'
CLASS_LIST = 'ScilabList'
BLOCK_AFFICHE = 'AfficheBlock'
BLOCK_BASIC = 'BasicBlock'
BLOCK_BIGSOM = 'BigSom'
BLOCK_EVENT_IN = 'EventInBlock'
BLOCK_EVENT_OUT = 'EventOutBlock'
BLOCK_EXPLICIT_IN = 'ExplicitInBlock'
BLOCK_EXPLICIT_OUT = 'ExplicitOutBlock'
BLOCK_GROUND = 'GroundBlock'
BLOCK_IMPLICIT_IN = 'ImplicitInBlock'
BLOCK_IMPLICIT_OUT = 'ImplicitOutBlock'
BLOCK_PRODUCT = 'Product'
BLOCK_ROUND = 'RoundBlock'
BLOCK_SPLIT = 'SplitBlock'
BLOCK_SUMMATION = 'Summation'
BLOCK_TEXT = 'TextBlock'
BLOCK_VOLTAGESENSOR = 'VoltageSensorBlock'
BLOCK_SUPER = 'SuperBlock'
BLOCKTYPE_C = 'c'
BLOCKTYPE_D = 'd'
BLOCKTYPE_H = 'h'
BLOCKTYPE_L = 'l'
BLOCKTYPE_X = 'x'
BLOCKTYPE_Z = 'z'
TYPE_INTEGER = 'ScilabInteger'
CLASS_TLIST = 'ScilabTList'
GEOMETRY = 'mxGeometry'
AS_REAL_PARAM = 'realParameters'
AS_INT_PARAM = 'integerParameters'
AS_NBZERO = 'nbZerosCrossing'
AS_NMODE = 'nmode'
AS_STATE = 'state'
AS_DSTATE = 'dState'
AS_OBJ_PARAM = 'objectsParameters'
AS_ODSTATE = 'oDState'
AS_EQUATIONS = 'equations'
TYPE_SUPER = 'SuperBlockDiagram'
TYPE_ADD = 'add'
TYPE_MODEL = 'mxGraphModel'
AS_MODEL = 'model'
TYPE_ROOT = 'root'
TYPE_MXCELL = 'mxCell'
TYPE_EVENTOUT = 'EventOutBlock'
AS_VALUE = 'OpAmp'
AS_EXPRS = 'exprs'
PORT_EXPLICITINPUT = 'ExplicitInputPort'
PORT_EXPLICITOUTPUT = 'ExplicitOutputPort'
PORT_IMPLICITINPUT = 'ImplicitInputPort'
PORT_IMPLICITOUTPUT = 'ImplicitOutputPort'
PORT_CONTROL = 'ControlPort'
PORT_COMMAND = 'CommandPort'
LINK_EXPLICIT = 'ExplicitLink'
LINK_IMPLICIT = 'ImplicitLink'
LINK_COMMANDCONTROL = 'CommandControlLink'
SCILAB_DIR = '../../scilab_for_xcos_on_cloud'
SCILAB_DIR = abspath(SCILAB_DIR)
SCILAB = join(SCILAB_DIR, 'bin', 'scilab-cli')
WORKSPACE = None
ANSI_ESCAPE_PATTERN = r'(?:\x1b\[[0-9;]*m)'
ANSI_ESCAPE = re.compile(ANSI_ESCAPE_PATTERN)
SCILAB_PROMPT = re.compile(rf'{ANSI_ESCAPE_PATTERN}*--> {ANSI_ESCAPE_PATTERN}*')
BACKSPACE = re.compile(r'.\x08')
# Following are system command which are not permitted in sci files
# (Reference scilab-on-cloud project)
SYSTEM_COMMANDS = (
r'ascii|dir\(|execstr|host|mputl|newfun|system|unix(_[gswx])?\('
)
SPECIAL_CHARACTERS = r'["\'\\]'
SCILAB_CURVE_C_SCI = "macros/Sources/CURVE_c.sci"
SCILAB_EXPRESSION_SCI = "macros/Misc/EXPRESSION.sci"
CONT_FRM_WRITE = "ajax-scilab/cont_frm_write.sci"
CLEANDATA_SCI_FUNC_WRITE = "ajax-scilab/scifunc-cleandata-do_spline.sci"
EXP_SCI_FUNC_WRITE = "ajax-scilab/expression-sci-function.sci"
GET_COLORMAP_VALUES_SCI_FUNC_WRITE = "ajax-scilab/get_colormap_values.sci"
RANDFUNC = "ajax-scilab/randfunc.sci"
INTERNAL = {
'getOutput': {
'scriptfiles': [CONT_FRM_WRITE],
'function': 'calculate_cont_frm',
'parameters': ['num', 'den'],
},
'getExpressionOutput': {
'scriptfiles': [SCILAB_EXPRESSION_SCI, EXP_SCI_FUNC_WRITE],
'function': 'callFunctionAcctoMethod',
'parameters': ['head', 'exx'],
},
'cleandata': {
'scriptfiles': [SCILAB_CURVE_C_SCI, CLEANDATA_SCI_FUNC_WRITE],
'function': 'callFunctioncleandata',
'parameters': ['xye'],
},
'do_Spline': {
'scriptfiles': [SCILAB_CURVE_C_SCI, CLEANDATA_SCI_FUNC_WRITE],
'function': 'callFunction_do_Spline',
'parameters': ['N', 'order', 'x', 'y'],
},
'get_colormap_values': {
'scriptfiles': [GET_COLORMAP_VALUES_SCI_FUNC_WRITE],
'function': 'getvaluesfromcolormap',
'parameters': ['colormapString'],
},
'randfunc': {
'scriptfiles': [RANDFUNC],
'function': 'randfunc',
'parameters': ['inputvalue'],
}
}
def load_variables(filename):
'''
add scilab commands to load only user defined variables
'''
command = "[__V1,__V2]=listvarinfile('%s');" % filename
command += "__V5=grep(string(__V2),'/^([124568]|1[07])$/','r');"
command += "__V1=__V1(__V5);"
command += "__V2=__V2(__V5);"
command += "__V5=grep(__V1,'/^[^%]+$/','r');"
command += "if ~isempty(__V5) then;"
command += "__V1=__V1(__V5);"
command += "__V2=__V2(__V5);"
command += "__V6=''''+strcat(__V1,''',''')+'''';"
command += "__V7='load(''%s'','+__V6+');';" % filename
command += "execstr(__V7);"
command += "end;"
command += "clear __V1 __V2 __V5 __V6 __V7;"
return command
def load_scripts():
# handle duplicate scriptfiles
scriptfiles = set()
for internal in INTERNAL.values():
for scriptfile in internal['scriptfiles']:
scriptfiles.add(scriptfile)
cmd = ''
for scriptfile in scriptfiles:
cmd += f"exec('{scriptfile}');"
p = 's'
cmd += f"{p}=poly(0,'{p}');"
p = 'z'
cmd += f"{p}=poly(0,'{p}');"
cmd += 'format(17);'
return cmd
class ScilabWorkspace:
def __init__(self, title, workspace, context=None):
self.title = title
self.workspace = workspace
self.context = context
cmd = load_scripts()
if workspace not in [None, '', 'None']:
print('workspace=', workspace)
cmd += load_variables(workspace)
if context not in [None, '', 'None']:
context = context.strip(' \t\n\r\f\v;')
if context:
context += ';'
msg = is_safe_string('context', context)
if not msg:
print(f'setting context={context}')
cmd += f"execstr('{context}');"
else:
print(f"Ignoring unsafe context {context}: {msg}")
scilab_cmd = [SCILAB,
"-noatomsautoload",
"-nogui",
"-nouserstartup",
"-nb",
"-e", cmd
]
env = os.environ.copy()
env['TERM'] = 'dumb'
self.child = pexpect.spawn(scilab_cmd[0], scilab_cmd[1:], env=env, encoding='utf-8', timeout=15)
self.child.expect(SCILAB_PROMPT)
def add_context(self, context):
if context in [None, '', 'None']:
return
msg = is_safe_string('context', context)
if msg:
print(f"Ignoring unsafe context {context}: {msg}")
return
if self.context == context:
print(f'context already set to {context}')
return
if self.context not in [None, '', 'None']:
print(f'adding new context={context}')
self.context += context
else:
print(f'setting context={context}')
self.context = context
self.send_command(f"execstr('{context}');")
def clean_output(self, text, expr):
# Remove echoed input and Scilab formatting
text = re.sub(ANSI_ESCAPE, '', text)
text = re.sub(BACKSPACE, '', text)
lines = [line.strip() for line in text.splitlines()]
if lines and lines[0] == expr:
lines = lines[1:]
text = '\n'.join(lines).strip()
return text
def send_expression(self, expression):
"""Send a line to the process and return its output"""
expression = expression.strip(' \t\n\r\f\v;')
if expression == '':
print('No expression')
return ''
expr = f'disp({expression})'
self.child.sendline(expr)
self.child.expect(SCILAB_PROMPT)
output = self.child.before.strip()
return self.clean_output(output, expr)
def send_command(self, command):
"""Send a line to the process and return its output"""
command = command.strip(' \t\n\r\f\v')
if command == '':
print('No command')
return ''
self.child.sendline(command)
self.child.expect(SCILAB_PROMPT)
output = self.child.before.strip()
return self.clean_output(output, command)
def clean(self):
"""Terminate the process cleanly"""
self.child.sendline('exit')
self.child.close()
self.child = None
def addNode(node, subNodeType, **kwargs):
subNode = ET.SubElement(node, subNodeType)
for key, value in kwargs.items():
if value is not None:
subNode.set(key, str(value))
return subNode
def addObjNode(node, subNodeType, scilabClass, type):
subNode = addDNode(node, subNodeType,
**{'as': type}, scilabClass=scilabClass)
return subNode
def addPrecisionNode(node, subNodeType, type, height, parameters):
width = 1 if height > 0 else 0
subNode = addAsDataNode(node,
subNodeType, type, height, width,
parameters, False, intPrecision='sci_int32')
return subNode
# BITSET
def addNodePrecision(node, subNodeType, height, parameters):
width = 1 if height > 0 else 0
subNode = addDataNode(node, subNodeType, height=1, width=width, intPrecision='sci_uint32')
for i, param in enumerate(parameters):
addDataData(subNode, param)
return subNode
def addTypeNode(node, subNodeType, type, height, parameters):
width = 1 if height > 0 else 0
subNode = addAsDataNode(node, subNodeType, type, height, width, parameters, False)
return subNode
# equations node start
def addArrayNode(node, scilabClass, **kwargs):
kwargs['scilabClass'] = scilabClass
return addDNode(node, 'Array', **kwargs)
def addScilabStringNode(node, width, parameters):
scilabStringNode = addDataNode(node, 'ScilabString', height=1, width=width)
for i, param in enumerate(parameters):
addDataData(scilabStringNode, param)
def addScilabBoolNode(node, width, parameters):
scilabBooleanNode = addDataNode(node, 'ScilabBoolean', height=1, width=width)
for i, param in enumerate(parameters):
addDataData(scilabBooleanNode, param)
def addScilabDNode(node, type, realParts, width):
height = 1 if width > 0 else 0
scilabDoubleNode = addADataNode(node, 'ScilabDouble', type, height, width)
for i, realPart in enumerate(realParts):
addDData(scilabDoubleNode, column=i, line=0, realPart=realPart)
return scilabDoubleNode
def addNodeScilabDB(node, type, realParts, height):
width = 1 if height > 0 else 0
scilabDoubleNode = addADataNode(node, 'ScilabDouble', type, height, width)
for i, realPart in enumerate(realParts):
addDData(scilabDoubleNode, column=i, line=0, realPart=realPart)
return scilabDoubleNode
def addScilabDoubleNode(node, realParts, width):
scilabDoubleNode = addDataNode(node, 'ScilabDouble', height=1, width=width)
for i, realPart in enumerate(realParts):
addDData(scilabDoubleNode, column=i, line=0, realPart=realPart)
def addNodeScilabDouble(node, realParts, height):
scilabDoubleNode = addDataNode(node, 'ScilabDouble', height=height, width=1)
for i, realPart in enumerate(realParts):
addDData(scilabDoubleNode, column=i, line=0, realPart=realPart)
def addDData(parent, column=None, line=None, realPart=None):
data_attributes = {}
if line is not None:
data_attributes['line'] = str(line)
if column is not None:
data_attributes['column'] = str(column)
if realPart is not None:
data_attributes['realPart'] = str(realPart)
data_element = ET.Element('data', attrib=data_attributes)
parent.append(data_element)
# equations node ends
def addgeometryNode(node, subNodeType, height, width, x, y):
geometryNode = addDtNode(node, subNodeType, **{'as': 'geometry'},
x=x, y=y, width=width, height=height)
return geometryNode
def addOutNode(node, subNodeType,
attribid, ordering, parent,
interface_func_name, simulation_func_name, simulation_func_type,
style, blockType,
**kwargs):
newkwargs = {'id': attribid, 'parent': parent,
'interfaceFunctionName': interface_func_name,
'blockType': blockType,
'simulationFunctionName': simulation_func_name,
'simulationFunctionType': simulation_func_type,
'style': style}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addData(node, column, line, value, isReal=False):
data = ET.SubElement(node, 'data')
data.set('line', str(line))
data.set('column', str(column))
if isinstance(value, (float, int)) or isReal:
data.set('realPart', str(value))
else:
data.set('value', value)
return data
DATA_HEIGHT = 0
DATA_WIDTH = 0
DATA_LINE = 0
DATA_COLUMN = 0
def addDataNode(node, subNodeType, **kwargs):
global DATA_HEIGHT, DATA_WIDTH, DATA_LINE, DATA_COLUMN
if 'height' in kwargs:
DATA_HEIGHT = kwargs['height']
if 'width' in kwargs:
DATA_WIDTH = kwargs['width']
DATA_LINE = 0
DATA_COLUMN = 0
subNode = addNode(node, subNodeType, **kwargs)
return subNode
def addAsDataNode(node, subNodeType, a, height, width, parameters, isReal, **kwargs):
newkwargs = {'as': a, 'height': height, 'width': width}
newkwargs.update(kwargs)
subNode = addDataNode(node, subNodeType, **newkwargs)
for param in parameters:
addDataData(subNode, param, isReal)
return subNode
def addADataNode(node, subNodeType, a, height, width):
newkwargs = {'as': a, 'height': height, 'width': width}
subNode = addDataNode(node, subNodeType, **newkwargs)
return subNode
def addDNode(node, subNodeType, **kwargs):
subNode = addNode(node, subNodeType, **kwargs)
return subNode
# for x & y in mxgeometry
def addDtNode(node, subNodeType, **kwargs):
subNode = addNode(node, subNodeType, **kwargs)
return subNode
def addDataData(node, value, isReal=False):
global DATA_HEIGHT, DATA_WIDTH, DATA_LINE, DATA_COLUMN
if DATA_LINE >= DATA_HEIGHT or DATA_COLUMN >= DATA_WIDTH:
print('Invalid: height=', DATA_HEIGHT, ',width=', DATA_WIDTH,
',line=', DATA_LINE, ',column=', DATA_COLUMN)
data = addData(node, DATA_COLUMN, DATA_LINE, value, isReal)
if DATA_LINE < DATA_HEIGHT - 1:
DATA_LINE += 1
else:
DATA_COLUMN += 1
return data
def addExprsNode(node, subNodeType, height, parameters):
width = 1 if height > 0 else 0
subNode = addDataNode(node, subNodeType, **{'as': 'exprs'},
height=height, width=width)
for i in range(height):
if i < len(parameters):
addDataData(subNode, parameters[i])
return subNode
def addExprsArrayNode(node, subSubNodeType, height, parameters,
codeLines, additionalSubNodeType, func_name):
subNode = addDataNode(node, TYPE_ARRAY, **{'as': 'exprs'},
scilabClass=CLASS_LIST)
subSubNode = addDataNode(subNode, subSubNodeType, height=height, width=1)
for i in range(height):
addDataData(subSubNode, parameters[i])
if additionalSubNodeType == TYPE_DOUBLE:
addDataNode(subNode, additionalSubNodeType, height=0, width=0)
elif additionalSubNodeType == TYPE_ARRAY:
nestedArrayNode = addDataNode(subNode, TYPE_ARRAY, scilabClass=CLASS_LIST)
addDataNode(nestedArrayNode, TYPE_DOUBLE, height=0, width=0)
elif additionalSubNodeType == TYPE_STRING:
if func_name == 'CONSTRAINT2_c':
nestedArrayNode = addDataNode(subNode, additionalSubNodeType, height=1, width=1)
addDataData(nestedArrayNode, '0')
nestedArrayNode = addDataNode(subNode, additionalSubNodeType, height=1, width=1)
addDataData(nestedArrayNode, '0')
elif func_name == 'DEBUG':
nestedArrayNode = addDataNode(subNode, additionalSubNodeType, height=1, width=1)
addDataData(nestedArrayNode, 'xcos_debug_gui(flag,block);')
return subNode
def getParametersFromExprsNode(node, subNodeType=TYPE_STRING):
parameters = []
if node is None:
pass
elif isinstance(node, dict):
parameters = node['parameters']
else:
tag = subNodeType + '[@as="exprs"]'
subNodes = node.find('./' + tag)
if subNodes is not None:
for data in subNodes:
value = data.attrib.get('value')
parameters.append(value)
else:
print(tag, ': Not found')
display_parameter = ''
eiv = ''
iiv = ''
con = ''
eov = ''
iov = ''
com = ''
return (parameters, display_parameter, eiv, iiv, con, eov, iov, com)
# Super Block Diagram
def addSuperNode(node, subNodeType,
a, background, gridEnabled,
title, **kwargs):
newkwargs = {'as': a, 'background': background,
'gridEnabled': gridEnabled,
'title': title}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addSuperBlkNode(node, subNodeType,
a, scilabClass,
**kwargs):
newkwargs = {'as': a, 'scilabClass': scilabClass}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def superAddNode(node, subNodeType,
value,
**kwargs):
newkwargs = {'value': value}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addmxGraphModelNode(node, subNodeType,
a,
**kwargs):
newkwargs = {'as': a}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addmxCellNode(node, subNodeType,
id,
**kwargs):
newkwargs = {'id': id}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addNodemxCell(node, subNodeType, a,
id,
**kwargs):
newkwargs = {'as': a, 'id': id}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addmxCell(node, subNodeType,
id,
**kwargs):
newkwargs = {'id': id}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addEventOutBlock(node, subNodeType,
id, parent,
interfaceFunctionName,
simulationFunctionName,
simulationFunctionType,
style, blockType,
dependsOnU, dependsOnT,
**kwargs):
newkwargs = {'id': id, 'parent': parent,
'interfaceFunctionName': interfaceFunctionName,
'simulationFunctionName':
simulationFunctionName,
'simulationFunctionType':
simulationFunctionType,
'style': style,
'blockType': blockType,
'dependsOnU': dependsOnU,
'dependsOnT': dependsOnT}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addPort(node, subNodeType,
id, parent, ordering,
initialState,
style, value,
**kwargs):
newkwargs = {'id': id, 'parent': parent,
'ordering': ordering,
'initialState': initialState,
'style': style, 'value': value}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addExplicitInputPort(root, id, parent, ordering, initialState,
style="ExplicitInputPort;align=left;verticalAlign=middle;spacing=10.0;rotation=0;flip=false;mirror=false",
value="",
**kwargs):
return addPort(root, PORT_EXPLICITINPUT,
id, parent, ordering,
initialState,
style, value,
**kwargs)
def addExplicitOutputPort(root, id, parent, ordering, initialState,
style="ExplicitOutputPort;align=right;verticalAlign=middle;spacing=10.0;rotation=0;flip=false;mirror=false",
value="",
**kwargs):
return addPort(root, PORT_EXPLICITOUTPUT,
id, parent, ordering,
initialState,
style, value,
**kwargs)
def addImplicitInputPort(root, id, parent, ordering, initialState,
style="ImplicitInputPort;align=left;verticalAlign=middle;spacing=10.0;rotation=0;flip=false;mirror=false",
value="",
**kwargs):
return addPort(root, PORT_IMPLICITINPUT,
id, parent, ordering,
initialState,
style, value,
**kwargs)
def addImplicitOutputPort(root, id, parent, ordering, initialState,
style="ImplicitOutputPort;align=right;verticalAlign=middle;spacing=10.0;rotation=0;flip=false;mirror=false",
value="",
**kwargs):
return addPort(root, PORT_IMPLICITOUTPUT,
id, parent, ordering,
initialState,
style, value,
**kwargs)
def addControlPort(root, id, parent, ordering, initialState,
style="ControlPort;align=center;verticalAlign=top;spacing=10.0;rotation=0;flip=false;mirror=false",
value="",
**kwargs):
return addPort(root, PORT_CONTROL,
id, parent, ordering,
initialState,
style, value,
**kwargs)
def addCommandPort(root, id, parent, ordering, initialState,
style="CommandPort;align=center;verticalAlign=bottom;spacing=10.0;rotation=0;flip=false;mirror=false",
value="",
**kwargs):
return addPort(root, PORT_COMMAND,
id, parent, ordering,
initialState,
style, value,
**kwargs)
def addLink(node, subNodeType, id, parent, source, target,
style, value, **kwargs):
newkwargs = {'id': id, 'parent': parent, 'source': source, 'target': target,
'style': style, 'value': value}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addExplicitLink(node, id, parent, source, target,
style=LINK_EXPLICIT, value="", **kwargs):
return addLink(node, LINK_EXPLICIT, id, parent, source, target,
style, value, **kwargs)
def addImplicitLink(node, id, parent, source, target,
style=LINK_IMPLICIT, value="", **kwargs):
return addLink(node, LINK_IMPLICIT, id, parent, source, target,
style, value, **kwargs)
def addCommandControlLink(node, id, parent, source, target,
style=LINK_COMMANDCONTROL, value="", **kwargs):
return addLink(node, LINK_COMMANDCONTROL, id, parent, source, target,
style, value, **kwargs)
def addGeoNode(node, subNodeType,
a,
**kwargs):
newkwargs = {'as': a}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addmxPointNode(node, subNodeType,
a, x, y,
**kwargs):
newkwargs = {'as': a, 'x': x, 'y': y}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addPointNode(node, subNodeType,
x, y,
**kwargs):
newkwargs = {'x': x, 'y': y}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
def addArray(node, subNodeType,
a,
**kwargs):
newkwargs = {'as': a}
newkwargs.update(kwargs)
return addNode(node, subNodeType, **newkwargs)
# OpAmp
def addSciStringNode(node, height, parameters):
scilabStringNode = addDataNode(node, 'ScilabString', height=height, width=1)
for i in range(height):
addDataData(scilabStringNode, parameters[i])
def addScilabDBNode(node, height):
addDataNode(node, 'ScilabDouble', height=height, width=0)
# Sine Voltage
def addTNode(node, subNodeType, type, width, parameters):
height = 1 if width > 0 else 0
subNode = addAsDataNode(node, subNodeType, type, height, width, parameters, False)
return subNode
def addSciDBNode(node, subNodeType, type, width, realParts):
height = 1 if width > 0 else 0
subNode = addAsDataNode(node, subNodeType, type, height, width, realParts, True)
return subNode
# DOLLAR_m
def addScilabIntNode(node, width, parameters):
height = 1 if width > 0 else 0
subNode = addDataNode(node, 'ScilabInteger', height=height, width=width,
intPrecision='sci_int8')
for i, param in enumerate(parameters):
addDataData(subNode, param)
return subNode
# Logic
def addSciIntNode(node, height, parameters):
width = 1 if height > 0 else 0
subNode = addDataNode(node, 'ScilabInteger', height=height, width=width,
intPrecision='sci_int8')
for i, param in enumerate(parameters):
addDataData(subNode, param)
return subNode
# CSCope
def addPrecNode(node, subNodeType, type, width, parameters):
height = 1 if width > 0 else 0
subNode = addAsDataNode(node,
subNodeType, type, height, width,
parameters, False, intPrecision='sci_int32')
return subNode
def addEquationsNode(node, scilabStringParameters=None,
additionalStringsArray=None,
parameterNames=None, parameters=None):
equationsArrayNode = addArrayNode(node, scilabClass="ScilabTList", **{'as': 'equations'})
if scilabStringParameters:
addScilabStringNode(equationsArrayNode, width=len(scilabStringParameters),
parameters=scilabStringParameters)
if additionalStringsArray:
for additionalStrings in additionalStringsArray:
additionalStringNode = addDataNode(equationsArrayNode,
'ScilabString',
height=1, width=len(additionalStrings))
for param in additionalStrings:
addDataData(additionalStringNode, param)
if parameterNames and parameters and len(parameterNames) == len(parameters):
innerArrayNode = addArrayNode(equationsArrayNode,
scilabClass="ScilabList")
addSciStringNode(innerArrayNode, len(parameterNames), parameterNames)
addNodeScilabDouble(innerArrayNode, height=len(parameters), realParts=[
format_real_number(x) for x in parameters
])
return equationsArrayNode
def strarray(parameter):
param = parameter[0].split(" ")
params = parameter[3].strip('[]').split(';')
parameters = ['-1', '1'] + [parameter[7]] + param + ['-1', '-1'] + params
return parameters
def stringtoarray(parameter):
array = re.split(r'[;, ]+', parameter)
return array
# Convert number into scientific notation
# Used by blocks Capacitor,ConstantVoltage,Inductor and Resistor
LOWER_LIMIT = 'lower_limit'
UPPER_LIMIT = 'upper_limit'
SIGN = 'sign'
VALUE = 'value'
def si_format(num):
lower_limit = -11
upper_limit = 15
number = float(num)
si_form = '{:.1e}'.format(number)
neg_prefixes = (
{SIGN: 'm', LOWER_LIMIT: -2, UPPER_LIMIT: 0, VALUE: 1E-3},
{SIGN: 'μ', LOWER_LIMIT: -5, UPPER_LIMIT: -3, VALUE: 1E-6},
{SIGN: 'n', LOWER_LIMIT: -8, UPPER_LIMIT: -6, VALUE: 1E-9},
{SIGN: 'p', LOWER_LIMIT: -11, UPPER_LIMIT: -9, VALUE: 1E-12})
pos_prefixes = (
{SIGN: '', LOWER_LIMIT: 1, UPPER_LIMIT: 3, VALUE: 1},
{SIGN: 'k', LOWER_LIMIT: 4, UPPER_LIMIT: 6, VALUE: 1E3},
{SIGN: 'M', LOWER_LIMIT: 7, UPPER_LIMIT: 9, VALUE: 1E6},
{SIGN: 'G', LOWER_LIMIT: 10, UPPER_LIMIT: 12, VALUE: 1E9},
{SIGN: 'T', LOWER_LIMIT: 13, UPPER_LIMIT: 15, VALUE: 1E12})
splits = si_form.split('e')
base = float(splits[0])
exp = int(splits[1])
if exp < lower_limit or exp > upper_limit:
return str(base) + ' 10^' + str(exp)
else:
if exp <= 0:
for p in neg_prefixes:
if exp >= p.get(LOWER_LIMIT) and exp <= p.get(UPPER_LIMIT):
return str(round(number / p.get(VALUE))) + ' ' + p.get(SIGN)
else:
for p in pos_prefixes:
if exp >= p.get(LOWER_LIMIT) and exp <= p.get(UPPER_LIMIT):
return str(round(number / p.get(VALUE))) + ' ' + p.get(SIGN)
def print_affich_m(rows, columns, prec):
s = '
'
for i in range(rows):
s += ''
for j in range(columns):
s += '{:.{prec}f} | '.format(0.0, prec=prec)
s += '
'
s += '
'
return s
def print_affich_m_by_param(p0, p5):
s = re.sub(r' *[\[\]] *', r'', p0)
rc = re.split(' *[;,] *', s)
rows = int(rc[0])
columns = int(rc[1])
prec = int(p5)
return print_affich_m(rows, columns, prec)
def get_value_min(value):
(v1, v2) = (value, re.sub(r'\([^()]*\)', r'', value))
while v1 != v2:
(v1, v2) = (v2, re.sub(r'\([^()]*\)', r'', v2))
return get_number_power(v1)
def get_number_power(value):
return re.sub(r'(\^|\*\*) *([a-zA-Z0-9]+|\([^()]*\)) *', r'\2',
value)
def convert_scientific_notation(parameter):
def repl(match):
if match.group('bare_exp'): # Case: '10^3' with no coefficient
return f"1e{match.group('bare_exp')}"
elif match.group('with_coeff'): # Case: '2*10^3' or '*10^3'
return 'e' + match.group('with_coeff')
elif match.group('fortran'): # Case: '1.23d4' or '1.23D4'
return f"{match.group('num')}e{match.group('exp')}"
return match.group(0) # Fallback (shouldn't happen)
pattern = re.compile(
r"(?P (?[-+]?\d+))"
r"|(?P\*?10\^(?P[-+]?\d+))"
r"|(?P(?P\d+\.?\d*)[dD](?P[-+]?\d+))",
re.VERBOSE
)
return pattern.sub(repl, parameter)
def format_real_number(parameter):
if type(parameter) is not str:
return parameter
if re.search(r'[a-zA-Z]', parameter): # Check if parameter contains alphabetic characters
if WORKSPACE is None:
print(f'No Scilab workspace available for {parameter} evaluation')
return parameter
msg = is_safe_string('parameter', parameter)
if msg:
print(f"Ignoring unsafe parameter {parameter}: {msg}")
return parameter
print(f'send {parameter} to Scilab')
parameter = WORKSPACE.send_expression(parameter)
print(f'received {parameter} from Scilab')
if re.search(r'^Undefined', parameter):
raise ValueError(f"Scilab workspace: {parameter}")
if not parameter.strip(): # Handle empty strings
return '0'
try:
parameter = convert_scientific_notation(parameter)
parameter = eval(parameter)
return "{:.17g}".format(float(parameter)) # Convert numeric strings safely
except ValueError:
return parameter # Return original non-numeric string
def format_real_numbers(parameters):
return [format_real_number(p) for p in parameters]
def num2str(num):
"""Converts a float to an integer first if it ends in .0."""
if num % 1 == 0:
num = int(num)
return str(num)
def get_max_exponent(polynomial, chr='s'):
exponents = []
regex = chr + r'\s*\^\s*\d+|' + chr
matches = re.findall(regex, polynomial)
if len(matches) == 0:
exponents.append(0)
else:
for match in matches:
splits = re.split(r'\s*\^\s*', match)
exponent = int(splits[1]) if len(splits) == 2 else 1
exponents.append(exponent)
return max(exponents)
def generate_id(block_count, port_count, link_count):
def random_hex(part1, sequence):
part3 = f"{sequence:x}"
return f"{part1}:{part3}"
part1 = f"{uuid.uuid4().int >> 64 & 0xffffffff:x}"
all_ids = [random_hex(part1, i) for i in range(block_count + port_count + link_count)]
block_ids = all_ids[0:block_count]
port_ids = all_ids[block_count:block_count + port_count]
link_ids = all_ids[block_count + port_count:block_count + port_count + link_count]
return block_ids, port_ids, link_ids
def style_to_object(style):
if not style.endswith(';'):
style += ';'
style_object = {}
remaining_style = style
while remaining_style:
index_of_key_value = remaining_style.find(';')
index_of_key = remaining_style.find('=')
if 0 < index_of_key < index_of_key_value:
key = remaining_style[:index_of_key]
value = remaining_style[index_of_key + 1:index_of_key_value]
style_object[key] = value
else:
key = 'default'
value = remaining_style[:index_of_key_value]
if value and key not in style_object:
style_object[key] = value
remaining_style = remaining_style[index_of_key_value + 1:]
return style_object
# parserfunction
def remove_hyphen_number(s):
return re.sub(r'-\d+$', '', s)
def get_int(s):
try:
return int(s)
except ValueError:
return -1
def getNextAttribId(attribid, nextattribid):
attribint = get_int(attribid)
if nextattribid <= attribint:
nextattribid = attribint + 1
return nextattribid
def checkModelTag(model):
if model.tag != 'mxGraphModel':
print(model.tag, '!= mxGraphModel')
sys.exit(102)
def checkXcosDiagramTag(diagram):
if diagram.tag != 'XcosDiagram' and diagram.tag != 'SuperBlockDiagram':
print(diagram.tag, '!= XcosDiagram')
sys.exit(102)
def checkRootTag(root):
if root.tag != 'root':
print('Not root')
sys.exit(102)
def createOutnode(i, outroot, rootattribid, parentattribid):
if i == 0:
outnode = ET.SubElement(outroot, 'mxCell')
outnode.set('id', rootattribid)
elif i == 1:
outnode = ET.SubElement(outroot, 'mxCell')
outnode.set('id', parentattribid)
outnode.set('parent', rootattribid)
else:
outnode = None
return outnode
def portType1(sType, sType2, tType2):
# port1
if sType == 'ExplicitLink':
if sType2 == 'ExplicitOutputPort' or sType2 == 'ExplicitLink':
return 'explicitInputPort'
else:
print('Error: (sourceType, sourceType2, targetType2) =',
'(', sType, ',', sType2, ',', tType2, ')')
elif sType == 'ImplicitLink':
if sType2 == 'ImplicitOutputPort' or sType2 == 'ImplicitLink':
return 'implicitInputPort'
else:
return 'implicitOutputPort'
elif sType == 'CommandControlLink':
if sType2 == 'CommandPort' or sType2 == 'CommandControlLink':
return 'controlPort'
else:
print('Error: (sourceType, sourceType2, targetType2) =',
'(', sType, ',', sType2, ',', tType2, ')')
else:
print('Error: (sourceType, sourceType2, targetType2) =',
'(', sType, ',', sType2, ',', tType2, ')')
def portType2(sType, sType2, tType2):
# port2
if sType == 'ExplicitLink':
if tType2 == 'ExplicitInputPort' or tType2 == 'ExplicitLink':
return 'explicitOutputPort'
else:
print('Error: (sourceType, sourceType2, targetType2) =',
'(', sType, ',', sType2, ',', tType2, ')')
elif sType == 'ImplicitLink':
if tType2 == 'ImplicitOutputPort' or tType2 == 'ImplicitLink':
return 'implicitInputPort'
else:
return 'implicitOutputPort'
elif sType == 'CommandControlLink':
if tType2 == 'ControlPort' or tType2 == 'CommandControlLink':
return 'commandPort'
else:
print('Error: (sourceType, sourceType2, targetType2) =',
'(', sType, ',', sType2, ',', tType2, ')')
def portType3(sType, tType):
# port3
if sType == 'ExplicitLink':
if tType == 'ExplicitInputPort' or tType == 'ExplicitLink':
return 'explicitOutputPort'
else:
print('Error: (sourceType, targetType) =',
'(', sType, ',', tType, ')')
elif sType == 'ImplicitLink':
if tType == 'ImplicitOutputPort' or tType == 'ImplicitLink':
return 'implicitInputPort'
else:
return 'implicitOutputPort'
elif sType == 'CommandControlLink':
if tType == 'ControlPort' or tType == 'CommandControlLink':
return 'commandPort'
else:
print('Error: (sourceType, targetType) =',
'(', sType, ',', tType, ')')
def addPort1ForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType, targetType, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, left_array):
if sourceType == 'ExplicitLink':
if sourceType2 == 'ExplicitOutputPort' or sourceType2 == 'ExplicitLink':
return addExplicitInputPortForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, left_array)
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
elif sourceType == 'ImplicitLink' or targetType == 'ImplicitLink':
if sourceType2 == 'ImplicitOutputPort' or targetType2 == 'ImplicitOutputPort':
return addImplicitInputPortForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, left_array)
else:
return addImplicitOutputPortForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, left_array)
elif sourceType == 'CommandControlLink':
if sourceType2 == 'CommandPort' or sourceType2 == 'CommandControlLink':
return addControlPortForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, left_array)
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
return (None, None, None, None)
def addPort2ForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType, targetType, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, right_array):
if sourceType == 'ExplicitLink':
if targetType2 == 'ExplicitInputPort' or targetType2 == 'ExplicitLink':
return addExplicitOutputPortForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, right_array)
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
elif sourceType == 'ImplicitLink' or targetType == 'ImplicitLink':
if targetType2 == 'ImplicitOutputPort' or sourceType2 == 'ImplicitOutputPort':
return addImplicitInputPortForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, right_array)
else:
return addImplicitOutputPortForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, right_array)
elif sourceType == 'CommandControlLink':
if targetType2 == 'ControlPort' or targetType2 == 'CommandControlLink':
return addCommandPortForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, right_array)
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
return (None, None, None, None)
def addPort3ForSplit(outroot, splitblockid, sourceVertex, targetVertex, sourceType, targetType, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, array3):
if sourceType == 'ExplicitLink':
if targetType == 'ExplicitInputPort':
return addExplicitOutputPortForSplit(outroot, splitblockid, sourceVertex, targetVertex, sourceType, targetType, inputCount, outputCount, nextattribid, nextAttribForSplit, array3)
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
elif sourceType == 'ImplicitLink' or targetType == 'ImplicitLink':
if targetType == 'ImplicitOutputPort' or sourceType == 'ImplicitOutputPort':
return addImplicitInputPortForSplit(outroot, splitblockid, sourceVertex, targetVertex, sourceType, targetType, inputCount, outputCount, nextattribid, nextAttribForSplit, array3)
else:
return addImplicitOutputPortForSplit(outroot, splitblockid, sourceVertex, targetVertex, sourceType, targetType, inputCount, outputCount, nextattribid, nextAttribForSplit, array3)
elif sourceType == 'CommandControlLink':
if targetType == 'ControlPort':
return addCommandPortForSplit(outroot, splitblockid, sourceVertex, targetVertex, sourceType, targetType, inputCount, outputCount, nextattribid, nextAttribForSplit, array3)
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
else:
print('Error: (sourceType, targetType, sourceType2, targetType2) =',
'(', sourceType, ',', targetType, ',', sourceType2, ',', targetType2, ')')
return (None, None, None, None)
def create_mxCell(style, id, vertex="1", connectable="0", CellType="Component", blockprefix="XCOS",
explicitInputPorts="0", explicitOutputPorts="0", implicitInputPorts="0", implicitOutputPorts="0", controlPorts="0", commandPorts="0",
simulationFunction="split", sourceVertex="0", targetVertex="0", tarx="0", tary="0", geometry=None):
mxCell = ET.Element("mxCell", {
"style": style,
"id": id,
"vertex": vertex,
"connectable": connectable,
"CellType": CellType,
"blockprefix": blockprefix,
"explicitInputPorts": str(explicitInputPorts),
"implicitInputPorts": str(implicitInputPorts),
"explicitOutputPorts": str(explicitOutputPorts),
"implicitOutputPorts": str(implicitOutputPorts),
"controlPorts": str(controlPorts),
"commandPorts": str(commandPorts),
"simulationFunction": simulationFunction,
"sourceVertex": sourceVertex,
"targetVertex": targetVertex,
"tarx": tarx,
"tary": tary,
})
if geometry:
x, y, width, height = geometry
ET.SubElement(mxCell, "mxGeometry", {
"x": str(x),
"y": str(y),
"width": str(width),
"height": str(height),
"as": "geometry"
})
ET.SubElement(mxCell, "Object", {
"display_parameter": str(),
"as": "displayProperties"
})
ET.SubElement(mxCell, "Object", {
"as": "parameter_values"
})
return mxCell
def create_mxCell_port(style, id, parentComponent, ordering="1", vertex="1", cellType="Pin",
sourceVertex="0", targetVertex="0", tarx="0", tary="0", geometry=None):
mxcell = ET.Element('mxCell', {
'style': style,
'id': str(id),
'ordering': ordering,
'vertex': vertex,
'CellType': cellType,
'ParentComponent': str(parentComponent),
'sourceVertex': sourceVertex,
'targetVertex': targetVertex,
'tarx': tarx,
'tary': tary,
})
if geometry:
x, y, width, height = geometry
mxgeometry = ET.SubElement(mxcell, 'mxGeometry', {
'x': str(x),
'y': str(y),
'width': str(width),
'height': str(height),
'relative': '1',
'as': 'geometry'
})
ET.SubElement(mxgeometry, 'mxPoint', {
'y': '-4',
'as': 'offset'
})
ET.SubElement(mxcell, "Object", {
"as": "parameter_values"
})
ET.SubElement(mxcell, "Object", {
"as": "displayProperties"
})
return mxcell
def create_mxCell_edge(id, edge="1", cellType="Unknown",
sourceVertex="0", targetVertex="0", tarx="0", tary="0", tar2x="0", tar2y="0", source_point="0", target_point="0", waypoints=None):
mxcell = ET.Element('mxCell', {
'id': str(id),
'edge': edge,
'CellType': cellType,
'sourceVertex': str(sourceVertex),
'targetVertex': str(targetVertex),
'tarx': tarx,
'tary': tary,
'tar2x': tar2x,
'tar2y': tar2y,
})
mxgeometry = ET.SubElement(mxcell, 'mxGeometry', {
'relative': '1',
'as': 'geometry'
})
ET.SubElement(mxgeometry, 'mxPoint', {
'x': str(source_point[0]),
'y': str(source_point[1]),
'as': 'sourcePoint'
})
ET.SubElement(mxgeometry, 'mxPoint', {
'x': str(target_point[0]),
'y': str(target_point[1]),
'as': 'targetPoint'
})
array_element = ET.SubElement(mxgeometry, 'Array', {
'as': 'points'
})
for waypoint in waypoints[1:-1]:
ET.SubElement(array_element, 'mxPoint', {
'x': waypoint['x'], # Access 'x' key
'y': waypoint['y'] # Access 'y' key
})
ET.SubElement(mxcell, "Object", {
"as": "parameter_values"
})
ET.SubElement(mxcell, "Object", {
"as": "displayProperties"
})
return mxcell
def check_point_on_array(array, point, left_right_direction=True):
if array is None:
return False, array, []
pointX = float(point['x'])
pointY = float(point['y'])
for i in range(len(array) - 1):
leftX = float(array[i]['x'])
leftY = float(array[i]['y'])
rightX = float(array[i + 1]['x'])
rightY = float(array[i + 1]['y'])
# Check if the point lies on the line segment between array[i] and array[i + 1]
pointbetweenleftrightx = leftX <= pointX <= rightX or leftX >= pointX >= rightX
samey = -40 <= leftY - pointY <= 40 and -40 <= rightY - pointY <= 40
sameleftorrighty = -20 <= leftY - pointY <= 20 or -20 <= rightY - pointY <= 20
if pointbetweenleftrightx and (samey or sameleftorrighty):
return True, array[:i + 1] + [point], [point] + array[i + 1:]
pointbetweenleftrighty = leftY <= pointY <= rightY or leftY >= pointY >= rightY
samex = -40 <= leftX - pointX <= 40 and -40 <= rightX - pointX <= 40
sameleftorrightx = -20 <= leftX - pointX <= 20 or -20 <= rightX - pointX <= 20
if pointbetweenleftrighty and (samex or sameleftorrightx):
return True, array[:i + 1] + [point], [point] + array[i + 1:]
# switch direction for the next waypoint
left_right_direction = not left_right_direction
return False, array, []
def identify_segment(array, point):
for i, waypoint in enumerate(array):
result, left_array, right_array = check_point_on_array(waypoint, point)
if result:
return result, i, left_array, right_array
print("Error:", point, "does not lie on", array)
return False, -1, array, []
def getOrdering(attrib, portCount, ParentComponent, orderingname):
try:
ordering = attrib['ordering']
except KeyError:
ordering = portCount[ParentComponent][orderingname]
return ordering
def switchPorts(sourceVertex, sourceType, targetVertex, targetType, waypoints):
# switch vertices if required
switch_split = False
if sourceType in ['ExplicitInputPort', 'ImplicitInputPort', 'ControlPort'] and \
targetType in ['ExplicitOutputPort', 'ExplicitLink', 'ImplicitOutputPort', 'ImplicitLink', 'CommandPort', 'CommandControlLink']:
(sourceVertex, targetVertex) = (targetVertex, sourceVertex)
(sourceType, targetType) = (targetType, sourceType)
waypoints.reverse()
switch_split = True
elif sourceType in ['ExplicitInputPort', 'ExplicitLink', 'ImplicitInputPort', 'ImplicitLink', 'ControlPort', 'CommandControlLink'] and \
targetType in ['ExplicitOutputPort', 'ImplicitOutputPort', 'CommandPort']:
(sourceVertex, targetVertex) = (targetVertex, sourceVertex)
(sourceType, targetType) = (targetType, sourceType)
waypoints.reverse()
switch_split = True
return (sourceVertex, sourceType, targetVertex, targetType, switch_split)
def getLinkStyle(attribid, sourceVertex, sourceType, targetVertex, targetType, waypoints):
(sourceVertex, sourceType, targetVertex, targetType, switch_split) = switchPorts(sourceVertex, sourceType, targetVertex, targetType, waypoints)
style = None
if sourceType in ['ExplicitInputPort', 'ExplicitOutputPort', 'CommandPort', 'ControlPort'] and \
targetType == sourceType:
print(attribid, 'cannot connect two ports of', sourceType, 'and', targetType)
elif sourceType in ['ExplicitLink', 'CommandControlLink'] and \
targetType == sourceType:
print(attribid, 'cannot connect two links of', sourceType, 'and', targetType)
elif sourceType in ['ExplicitOutputPort', 'ExplicitLink'] and \
targetType in ['ExplicitInputPort', 'ExplicitLink']:
style = 'ExplicitLink'
elif sourceType in ['ImplicitOutputPort', 'ImplicitInputPort', 'ImplicitLink'] and \
targetType in ['ImplicitInputPort', 'ImplicitOutputPort', 'ImplicitLink']:
style = 'ImplicitLink'
elif sourceType in ['CommandPort', 'CommandControlLink'] and \
targetType in ['ControlPort', 'CommandControlLink']:
style = 'CommandControlLink'
else:
print(attribid, 'Unknown combination of', sourceType, 'and', targetType)
addSplit = sourceType.endswith('Link') or targetType.endswith('Link')
return (sourceVertex, sourceType, targetVertex, targetType, switch_split, style, addSplit, waypoints)
def initLinks(attribid, graph_value, removable_value, key1, graph_link, removable_link):
# for ports, the graph_value and the removable_value are empty lists
# for links, the graph_value is a list containing itself and the
# removable_value is a list containing itself if it has a split point and an
# empty list otherwise
key1[attribid] = attribid
graph_link[attribid] = graph_value
removable_link[attribid] = removable_value
def mergeLinks(attribid, vertex, key1, graph_link, removable_link):
# for links only
# merge the ports/links of the source/target vertex into itself
# also, remove the ports/links of the source/target vertex
if vertex in key1:
key = key1[vertex]
for v in graph_link[key]:
key1[v] = attribid
graph_link[attribid].extend(graph_link[key])
removable_link[attribid].extend(removable_link[key])
del graph_link[key]
del removable_link[key]
def getlinkdetails(port, sourceVertex2, targetVertex2, otherVertex, tarx, tary, tar2x, tar2y, otherx, othery,
left_array, right_array, array3, biglinkid, smalllinkid):
if port == 0:
port_index = sourceVertex2
portx = tarx
porty = tary
waypoints = left_array
linkid = biglinkid
elif port == 1:
port_index = targetVertex2
portx = tar2x
porty = tar2y
waypoints = right_array
linkid = biglinkid
else:
port_index = otherVertex
portx = otherx
porty = othery
waypoints = array3
linkid = smalllinkid
return port_index, portx, porty, waypoints, linkid
def addtolinklist(port, explicitInputPorts, explicitOutputPorts, implicitInputPorts, implicitOutputPorts, controlPorts, commandPorts,
port_id, thisx, thisy, port_index, portx, porty, waypoints, linkid, linklist):
if port < explicitInputPorts:
port_type = "ExplicitInputPort"
link_type = "ExplicitLink"
linklist.append((link_type, port_id, thisx, thisy, port_index, portx, porty, waypoints, linkid))
elif port < explicitInputPorts + implicitInputPorts:
port_type = "ImplicitInputPort"
link_type = "ImplicitLink"
linklist.append((link_type, port_id, thisx, thisy, port_index, portx, porty, waypoints, linkid))
elif port < explicitInputPorts + implicitInputPorts + explicitOutputPorts:
port_type = "ExplicitOutputPort"
link_type = "ExplicitLink"
linklist.append((link_type, port_index, portx, porty, port_id, thisx, thisy, waypoints, linkid))
elif port < explicitInputPorts + implicitInputPorts + explicitOutputPorts + implicitOutputPorts:
port_type = "ImplicitOutputPort"
link_type = "ImplicitLink"
linklist.append((link_type, port_index, portx, porty, port_id, thisx, thisy, waypoints, linkid))
elif port < explicitInputPorts + implicitInputPorts + explicitOutputPorts + implicitOutputPorts + controlPorts:
port_type = "ControlPort"
link_type = "CommandControlLink"
linklist.append((link_type, port_id, thisx, thisy, port_index, portx, porty, waypoints, linkid))
else:
port_type = "CommandPort"
link_type = "CommandControlLink"
linklist.append((link_type, port_index, portx, porty, port_id, thisx, thisy, waypoints, linkid))
return port_type, link_type
def getComponentGeometry(mxGeometry):
componentGeometry = {}
componentGeometry['height'] = 40
componentGeometry['width'] = 40
componentGeometry['x'] = 0
componentGeometry['y'] = 0
if mxGeometry is not None:
componentGeometry['height'] = mxGeometry.attrib['height']
componentGeometry['width'] = mxGeometry.attrib['width']
componentGeometry['x'] = mxGeometry.attrib.get('x', '0')
componentGeometry['y'] = mxGeometry.attrib.get('y', '0')
return componentGeometry
def getPinGeometry(mxGeometry, componentGeometry):
geometry = dict(componentGeometry)
if mxGeometry is not None:
geometry['height'] = mxGeometry.attrib['height']
geometry['width'] = mxGeometry.attrib['width']
geometryX = mxGeometry.attrib.get('x', 0)
geometryY = mxGeometry.attrib.get('y', 0)
if mxGeometry.attrib.get('relative', '0') == '1':
geometryX = num2str(float(componentGeometry['x']) +
float(componentGeometry['width']) * float(geometryX))
geometryY = num2str(float(componentGeometry['y']) +
float(componentGeometry['height']) * float(geometryY))
geometry['x'] = geometryX
geometry['y'] = geometryY
return geometry
def getorderingname(stylename):
if stylename == 'ImplicitInputPort':
orderingname = 'ExplicitInputPort'
elif stylename == 'ImplicitOutputPort':
orderingname = 'ExplicitOutputPort'
else:
orderingname = stylename
return orderingname
def getParameters(cell):
parameter_values = cell.find('./Object[@as="parameter_values"]')
parameters = []
if parameter_values is not None:
parameter_values = parameter_values.attrib
for i in range(100):
parameter = 'p%03d_value' % i
if parameter in parameter_values:
parameters.append(parameter_values[parameter])
else:
break
return parameters
def getSuperblock(cell):
if "style" in cell.attrib and "SUPER_f" in cell.attrib["style"]:
mxGraphModel = cell.find("./SuperBlockDiagram")
return mxGraphModel
return None
def getWaypoints(mxGeometry):
waypoints = []
arrayElement = mxGeometry.find('Array')
if arrayElement is not None:
for arrayChild in arrayElement:
if arrayChild.tag == 'mxPoint':
waypoints.append(arrayChild.attrib)
return waypoints
def getSplitPoints(attrib, switch_split, blkgeometry, sourceVertex, targetVertex, waypoints):
split_point, split_point2 = None, None
if 'tarx' in attrib and 'tary' in attrib and (attrib['tarx'] != '0' or attrib['tary'] != '0'):
point = {'x': attrib['tarx'], 'y': attrib['tary']}
if switch_split:
split_point2 = point
waypoints.append(point)
else:
split_point = point
waypoints.insert(0, point)
elif sourceVertex in blkgeometry:
vertex = blkgeometry[sourceVertex]
point = {'x': vertex['x'], 'y': vertex['y']}
waypoints.insert(0, point)
if 'tar2x' in attrib and 'tar2y' in attrib and (attrib['tar2x'] != '0' or attrib['tar2y'] != '0'):
point = {'x': attrib['tar2x'], 'y': attrib['tar2y']}
if switch_split:
split_point = point
waypoints.insert(0, point)
else:
split_point2 = point
waypoints.append(point)
elif targetVertex in blkgeometry:
vertex = blkgeometry[targetVertex]
point = {'x': vertex['x'], 'y': vertex['y']}
waypoints.append(point)
return split_point, split_point2
def createDefaultParent(parentattribid, rootattribid):
defaultParent = ET.Element('mxCell')
defaultParent.set('as', 'defaultParent')
defaultParent.set('id', parentattribid)
defaultParent.set('parent', rootattribid)
return defaultParent
def process_xcos_model(diagram, title, rootattribid, parentattribid,
workspace_file=None, context=None):
global WORKSPACE
started_workspace = False
if WORKSPACE is None:
WORKSPACE = ScilabWorkspace(title, workspace_file, context)
started_workspace = True
checkXcosDiagramTag(diagram)
context_array = diagram.find('Array[@as="context"]')
if context_array is not None:
context = ''
for context_add in context_array:
if context_add.tag == 'add':
context_value = context_add.attrib['value']
if context_value:
context_value = context_value.strip(' \t\n\r\f\v;')
if context_value:
context += context_value + ';'
if context:
WORKSPACE.add_context(context)
model = diagram.find('mxGraphModel')
checkModelTag(model)
outmodel = ET.Element('mxGraphModel')
outmodel.set('as', 'model')
for root in model:
checkRootTag(root)
outroot = ET.SubElement(outmodel, 'root')
portCount = {}
IDLIST = {}
componentOrdering = 0
nextattribid = 1
nextAttribForSplit = 10000
edgeDict = {}
edgeList = []
blkgeometry = {}
cells = list(root)
remainingcells = []
cellslength = len(cells)
oldcellslength = 0
print('cellslength=', cellslength)
while cellslength > 0 and cellslength != oldcellslength:
for i, cell in enumerate(cells):
try:
if i <= 1 and oldcellslength == 0:
createOutnode(i, outroot, rootattribid, parentattribid)
continue
attrib = cell.attrib
if 'id' not in attrib:
continue
attribid = attrib['id']
nextattribid = getNextAttribId(attribid, nextattribid)
# cell_type = attrib['CellType']
cell_type = attrib.get('CellType')
mxGeometry = cell.find('mxGeometry')
if cell_type == 'Component':
style = attrib['style']
componentOrdering += 1
portCount[attribid] = {
'ExplicitInputPort': 0,
'ImplicitInputPort': 0,
'ControlPort': 0,
'ExplicitOutputPort': 0,
'ImplicitOutputPort': 0,
'CommandPort': 0
}
componentGeometry = getComponentGeometry(mxGeometry)
parameters = getParameters(cell)
superblock = getSuperblock(cell)
# print(style_to_object(style))
# stylename = style_to_object(style)['default']
style_dict = style_to_object(style)
stylename = style_dict.get('default', 'TEXT_f')
getattr(Blocks, stylename)(outroot, attribid, componentOrdering, componentGeometry, parameters,
parent=parentattribid, style=style, superblock=superblock)
IDLIST[attribid] = cell_type
blkgeometry[attribid] = componentGeometry
elif 'vertex' in attrib:
style = attrib['style']
stylename = style_to_object(style)['default']
ParentComponent = attrib['ParentComponent']
orderingname = getorderingname(stylename)
portCount[ParentComponent][orderingname] += 1
ordering = getOrdering(attrib, portCount, ParentComponent, orderingname)
geometry = getPinGeometry(mxGeometry, componentGeometry)
getattr(Ports, stylename)(outroot, attribid, ParentComponent, ordering, geometry, style=style)
IDLIST[attribid] = stylename
blkgeometry[attribid] = geometry
elif 'edge' in attrib:
waypoints = getWaypoints(mxGeometry)
sourceVertex = attrib['sourceVertex']
targetVertex = attrib['targetVertex']
if sourceVertex not in IDLIST or targetVertex not in IDLIST:
remainingcells.append(cell)
continue
sourceType = IDLIST[sourceVertex]
targetType = IDLIST[targetVertex]
(sourceVertex, sourceType, targetVertex, targetType, switch_split, style, addSplit, waypoints) = getLinkStyle(attribid, sourceVertex, sourceType, targetVertex, targetType, waypoints)
split_point, split_point2 = getSplitPoints(attrib, switch_split, blkgeometry, sourceVertex, targetVertex, waypoints)
IDLIST[attribid] = style
link_data = (attribid, sourceVertex, targetVertex, sourceType, targetType, style, waypoints, addSplit, split_point, split_point2)
edgeDict[attribid] = link_data
edgeList.append(link_data)
except Exception:
traceback.print_exc()
sys.exit(127)
oldcellslength = cellslength
cells = remainingcells
cellslength = len(remainingcells)
remainingcells = []
print('cellslength=', cellslength, ', oldcellslength=', oldcellslength)
newEdgeDict = {}
LINKTOPORT = {}
for (attribid, sourceVertex, targetVertex, sourceType, targetType, style, waypoints, addSplit, split_point, split_point2) in edgeList:
link_data = (attribid, sourceVertex, targetVertex, sourceType, targetType, style, waypoints, addSplit, split_point, split_point2)
if not addSplit:
newEdgeDict[attribid] = [link_data]
continue
for attribid2 in sourceVertex, targetVertex:
try:
linkSegments = newEdgeDict[attribid2]
except KeyError:
continue
print('split_point:', split_point, linkSegments)
if attribid2 == sourceVertex:
splitpoint = split_point
else:
splitpoint = split_point2
result, i, left_array, right_array = identify_segment(linkSegments, splitpoint)
if not result:
sys.exit(0)
(linkid, sourceVertex2, targetVertex2, sourceType2, targetType2, style2, waypoints2, addSplit2, split_point_new, split_point2_new) = linkSegments[i]
array3 = waypoints
componentOrdering += 1
geometry = {}
geometry['height'] = 7
geometry['width'] = 7
geometry['x'] = splitpoint['x']
geometry['y'] = splitpoint['y']
if sourceType2 == 'ControlPort' or sourceType2 == 'CommandPort' or sourceType2 == 'CommandControlLink':
split_style = 'CLKSPLIT_f'
func_name = 'CLKSPLIT_f'
else:
split_style = 'SPLIT_f;flip=false;mirror=false'
func_name = 'SPLIT_f'
SplitBlock(outroot, nextattribid, componentOrdering, geometry, [], parent=parentattribid, style=split_style, func_name=func_name)
splitblockid = nextattribid
nextattribid += 1
inputCount = 0
outputCount = 0
port1 = nextattribid
(inputCount, outputCount, nextattribid, nextAttribForSplit) = addPort1ForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType, targetType, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, left_array)
port2 = nextattribid
(inputCount, outputCount, nextattribid, nextAttribForSplit) = addPort2ForSplit(outroot, splitblockid, sourceVertex2, targetVertex2, sourceType, targetType, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, right_array)
port3 = nextattribid
(inputCount, outputCount, nextattribid, nextAttribForSplit) = addPort3ForSplit(outroot, splitblockid, sourceVertex, targetVertex, sourceType, targetType, sourceType2, targetType2, inputCount, outputCount, nextattribid, nextAttribForSplit, array3)
newEdgeDict[attribid2][i] = ((nextAttribForSplit, sourceVertex2, port1, sourceType2, targetType, style2, left_array, addSplit2, split_point, split_point2))
nextAttribForSplit += 1
newEdgeDict[attribid2].insert(i + 1, (nextAttribForSplit, port2, targetVertex2, sourceType, targetType2, style2, right_array, addSplit2, split_point, split_point2))
nextAttribForSplit += 1
if attribid2 == sourceVertex:
waypoints.reverse()
newEdgeDict[attribid] = [(nextAttribForSplit, port3, targetVertex, sourceType, targetType, style, waypoints, addSplit, split_point, split_point2)]
else:
newEdgeDict[attribid] = [(nextAttribForSplit, port3, sourceVertex, sourceType, targetType, style, waypoints, addSplit, split_point, split_point2)]
nextAttribForSplit += 1
LINKTOPORT[linkid] = port3
for key, newEdges in newEdgeDict.items():
for (attribid, sourceVertex, targetVertex, sourceType, targetType, style, waypoints, addSplit, split_point, split_point2) in newEdges:
try:
sourceVertex = LINKTOPORT[sourceVertex]
except KeyError:
pass
try:
targetVertex = LINKTOPORT[targetVertex]
except KeyError:
pass
if get_int(attribid) >= 10000:
attribid = nextattribid
nextattribid += 1
getattr(Links, style)(outroot, attribid, sourceVertex, targetVertex, waypoints[1:-1], parent=parentattribid)
if started_workspace:
print('Terminating workspace')
WORKSPACE.clean()
WORKSPACE = None
started_workspace = False
return outmodel
def is_safe_string(parameter, value):
try:
value.encode('ascii')
except UnicodeEncodeError:
return f"{parameter} parameter has non-ascii characters"
if re.search(SYSTEM_COMMANDS, value):
return f"{parameter} parameter has unsafe value"
if re.search(SPECIAL_CHARACTERS, value):
return f"{parameter} parameter has value with special characters"
return None
def internal_fun(internal_key, **kwargs):
try:
internal = INTERNAL[internal_key]
function = internal['function']
parameters = internal['parameters']
cmd = ""
file_name = f"{WORKSPACE.title}-{internal_key}.txt"
cmd += f"{function}('{file_name}'"
for parameter in parameters:
value = kwargs[parameter]
msg = is_safe_string(parameter, value)
if msg:
print(msg)
return {'msg': msg}
cmd += f",{value}" if 'num' in parameters else f",'{value}'"
cmd += ");"
print(f"send command {cmd} to Scilab")
WORKSPACE.send_command(cmd)
if not isfile(file_name):
msg = f"output {file_name} does not exist"
print(msg)
return {'msg': msg}
with open(file_name, 'r') as f:
data = f.read()
data = ast.literal_eval(data)
# flatten only if data is a list of lists with length 1
if type(data) is list and \
all(type(item) is list and len(item) == 1 for item in data):
data = [item[0] for item in data]
print(f"data: {data}")
os.remove(file_name)
return data
except Exception as e:
msg = f"Error in internal function '{internal_key}': {str(e)}"
print(msg)
return {'msg': msg}
def cont_frm(num, den):
return internal_fun('getOutput', num=num, den=den)