Frame provides the basis for setting up a CAD/CAE/CIM solution. General facilities for List handling, Error handling, Command decoding, Application module binding, Interactive optical feedback and Mathematical Basics are covered.
In the recommended way of use, a last-in-first-out (LIFO) concept is used, which means that lists normally grow from the tail towards their head. The head is normally the end where new nodes are added (That's the fastest way). It is also possible to insert new nodes anywhere in the list. The LIFO method is fast and allows coincidence of current element and list head.
All functions and macros of this list-type end with the postfix_list
or
postfix_node
. The type of node and list-head pointers is struct list_node
.
me_front_add_node
)
me_add_node
)
me_del_list
)
me_del_node
)
me_count_nodes
)
me_get_next_node
)
me_get_objptr_of_node
)
me_reverse_list
)
me_exchange_link_of_node
)
There are two different principles dealing with errors:
Error codes will be returned whenever it is likely that the calling routine can deal with the error.
A set of macros is used to trap so-called exceptions (longjumps). Exceptions may be generated EVERYWHERE in the code. Even if a procedure returning an error code is called, an exception may lead to a premature exit from that routine.
Exceptions can be handled at certain strategic places as described in the next section.
The ME_TRY
, ME_RECOVER
, ME_END_TRY
macros allow
programmatic trapping of:
ME_ESCAPE
.
The macro ME_ESCAPE
allows the generation of longjumps.
General Macro Usage:
ME_TRY
| |
<statements> | |
ME_RECOVER
| |
<statements> | |
ME_END_TRY
|
The macros ME_TRY, ME_RECOVERY, and ME_END_TRY are based on calls of setjump. Be careful if you use setjump or these macros together with global optimization switched on during compilation. Due to global optimization, non-volatile variables may have been overwritten if the RECOVER block is entered (by a longjump).
When ME_TRY
is executed, certain information about the state of the
program is recorded in a marker called the 'environment',
which is pushed onto the program's stack. The address of the environment
is saved in the global variable me_env_ptr
, then the statements
following the ME_TRY
are executed in sequence. If none of them
causes an exception, the ME_RECOVER
is reached, its statements
are skipped, and the environment is popped off the stack.
But if an exception occurs such as signal received, math error occurred or
ME_ESCAPE
executed, the stack is restored to the state indicated by
the most recent environment. If ME_TRY
- ME_RECOVER
- ME_END_TRY
was
itself nested within another one, or within procedures called while a
ME_TRY
- ME_RECOVER
- ME_END_TRY
was active, the outer environment
becomes active. Then the statements following ME_RECOVER
are executed.
Thus nesting of ME_TRY
- ME_RECOVER
- ME_END_TRY
is DYNAMIC,
according to calling sequence, and not statically structured.
ME_TRY
or the ME_RECOVER
block with
return
or goto
statements.
The recovery process does not 'undo' the computational effects of
statements between ME_TRY
and ME_RECOVER
. The exception simply aborts the
computation and the program continues with the 'recover' statements.
When an exception has been caught, the global variable me_errno
contains
the number of the exception.
Exceptions can be simulated by using the macro ME_ESCAPE
(code),
which sets the exception code to 'code' and does a longjump.
A well structured example for error handling may look like this:
ME_TRY { statement1; statement2; . . } ME_RECOVER switch (me_errno) { case ME_SYS_ERROR: recover_statement1; recover_statement2; . . break; default: ME_ESCAPE(me_errno); break; } ME_END_TRY
The default
branch in the switch statement ensures that unwanted
errors are passed on to the next ME_TRY
...
block, so there should be at least one ME_TRY
... where
transferred errors are processed !
Related Macros:
ME_TRY
ME_RECOVER
ME_END_TRY
ME_ESCAPE
Symbol | Description |
---|---|
ME_NO_EXCEPTION
| |
ME_SYS_ERROR
| System Call returned an error; Error code defined in errno
|
ME_SIGNAL
| Signal has been received; See me_signalno
|
ME_MATH_ERROR
| A math error has occurred; Error code is defined in me_math_error
|
ME_EX_NOMEM
| Not enough memory |
ME_EX_NILPTR
| Reference to NIL pointer
|
ME_GLOBAL_GOTO
| ESCAPE used for a global goto
|
Keywords are reserved words within ME10. They start with a
letter which may be followed by letters, digits, or the _
character.
All letters have to be uppercase.
There are several types of keywords:
Command and function keywords such as LINE
and REDRAW
will
start their corresponding action routine when typed by the user.
Qualifiers such as DEL_OLD
and TWO_POINTS
do not have an action
routine of their own; they are used by other commands and
functions to select one of many options for that command or
function.
Pseudo_commands such as IF
and END_LOOP
are only used internally, they
control the execution of macros.
Arithm_functions such as SIN
and SQRT
are used within expressions.
Their associated C function has to pick up the necessary
parameters and to calculate the function result.
The following routines are used to define new keywords. They all return a pointer to an internal data structure describing the keyword. This pointer may be used later to check if some keyword pointer is pointing to the keyword just created.
struct keyword *me_new_command(name, func) char *name; void (*func)(); struct keyword *me_new_function(name, func) char *name; void (*func)(); struct keyword *me_new_qualifier(name) char *name; struct keyword *me_new_arithm_function(name, func) char *name; struct token *func;
name
is the command name at the user interface level
and the func
is the procedure name at the AI level
performing the related command.
Processing ME10 input can be split into two parts: character processing and token processing. All logical input devices, such as the keyboard or a screen/tablet menu, send characters to the scanner. The scanner understands the syntax of all token types. It decides by looking at the stream of characters if the token is a point, a string or a number.
Basically a token is an entity of information containing a token type, a value, and a link to next token.
All input from the user is classified, converted, and packaged for easy parsing by action routines. These information packages are called tokens. There are several types of tokens, each carrying a different kind of information:
COMMAND_TOKEN
FUNCTION_TOKEN
QUALIFIER_TOKEN
PSEUDO_COMMAND_TOKEN
ARITHM_FUNCTION_TOKEN
The information carried by these token types is a pointer to
their keyword. Normal action routines will never see
PSEUDO_COMMAND
or ARITHM_FUNCTION
tokens, as these are handled
internally. This means those will be processed before being handed over
to the action routines.
COMMAND_TOKEN
END
.
Commands may be interrupted temporarily by Functions.
LINE
FUNCTION_TOKEN
WINDOW
QUALIFIER_TOKEN
DOT_CENTER
PSEUDO_COMMAND_TOKEN
LOCAL
ARITHM_FUNCTION_TOKEN
SIN(3.14)
SYMBOL_TOKEN
SYM_AMPERSAND | 0
|
SYM_ASTERISK | 1
|
SYM_AT | 2
|
SYM_CARET | 3
|
SYM_COLON | 4
|
SYM_COMMA | 5
|
SYM_DASH | 6
|
SYM_DOLLAR_SIGN | 7
|
SYM_EQUAL | 8
|
SYM_EXCLAMATION_POINT | 9
|
SYM_GRAVE_ACCENT | 10
|
SYM_GREATER | 11
|
SYM_GREATER_EQUAL | 12
|
SYM_LEFT_BRACKET | 13
|
SYM_LEFT_PAREN | 14
|
SYM_LESS | 15
|
SYM_LESS_EQUAL | 16
|
SYM_NOT_EQUAL | 17
|
SYM_PERCENT | 18
|
SYM_PERIOD | 19
|
SYM_PLUS | 20
|
SYM_QUESTION_MARK | 21
|
SYM_RIGHT_BRACKET | 22
|
SYM_RIGHT_PAREN | 23
|
SYM_SEMICOLON | 24
|
SYM_SLASH | 25
|
SYM_TILDE | 26
|
SYM_VERTICAL_BAR | 27
|
MACRO_TOKEN
MACRO
token, as macros are substituted
(expanded)
with their definition before being passed to an action routine.
STRING_TOKEN
NUMBER_TOKEN
type float64
).
3.14
POINT_TOKEN
type
struct fvec2
).
3.14,3.14
ILLEGAL_TOKEN
1,a
NO_TOKEN
NO_TOKEN
for example, is generated if a
function was successfully terminated. See below.
The following routines deal with tokens:
int me_token_get(prompt)
char *prompt; |
|
void me_token_unget() |
This routine returns a token, read in by me_token_get() , to the
ME10 system. This should be done for all tokens that the
current action routine cannot or will not handle.
The following routines are used to retrieve the information
associated with the token read by |
struct keyword *me_token_keyword() | Contains the keyword pointer
from a COMMAND_TOKEN , FUNCTION_TOKEN , QUALIFIER_TOKEN ,
PSEUDO_COMMAND_TOKEN , or ARITHM_FUNCTION_TOKEN .
|
int me_token_symbol() | Retrieves the symbol type from
a SYMBOL_TOKEN .
|
char *me_token_string() | Contains the pointer to the character
string of a STRING_TOKEN .
|
float64 me_token_number() | Contains the double-precision number
of a NUMBER_TOKEN .
|
struct fvec2 me_token_pnt2d() | Contains the 2D point of
a POINT_TOKEN .
|
The following functions are general support functions for writing action routines:
void me_display_prompt(prompt)
char *prompt; |
This routine will show the prompt string on the system prompt line. |
void me_token_error() |
This routine should be called if the user has entered an illegal token
for an action routine.
It clears all input buffers, issues a beep, and then starts
error-processing if an ON_ERROR is active.
|
void me_wait_for_ack() | This routine waits for the user to press a key on the keyboard, the mouse or the tablet stylus. It may be used to give the user some time to read a message, before it is overwritten by the next input prompt. |
void me_display_error(prompt)
char *prompt; |
This is a convenient combination of |
void me_set_default_input(s)
char *s; |
This routine provides a default for the next user input. This default is put on the input line and may be edited by the user. The default is ignored if the input request can be satisfied from an executing macro, an input file or previously buffered user input. |
This is an example where a number_token and a qualifier token takes
place. The task it performs is: When the user inputs numbers
in a sequence and then finally types in DONE
, it prints out
the average value.
UNIX-Based Systems:
#include "frame.h" #include "model2d.h" static struct keyword *keyword_done; /*---------------------------------------------*/ static void ai_demo_fnc() { char buf[1024]; float64 sum = 0.0; int n = 0; for (;;) switch (me_token_get("Enter a number or DONE")) { case COMMAND_TOKEN: case FUNCTION_TOKEN: me_token_unget(); return; case QUALIFIER_TOKEN: if (me_token_keyword() == keyword_done) { if (n) { sprintf(buf, "The average of your %d numbers is %.16g", n, sum / n); me_display_prompt(buf); me_wait_for_ack(); } return; } me_token_error(); break; case NUMBER_TOKEN: sum += me_token_number(); n+ +; break; case NO_TOKEN: break; default: me_token_error(); break; } } /*----------------------------------------------*/ void ai_initialize() { static int initialized; if (initialized+ +) return; me_new_function("AI_DEMO", ai_demo_fnc); keyword_done = me_new_qualifier("DONE"); }
Windows-Based Systems:
#include <math.h> #include <setjmp.h> #include <stdio.h> #include <string.h> #include "../frame.h" #include "../model2d.h" struct keyword *keyword_done; /*---------------------------------------------------------------------------*/ void ai_demo_fnc() { char buf[1024]; float64 sum = 0.0; int n = 0; for (;;) switch (me_token_get("Enter a number or DONE")) { case COMMAND_TOKEN: case FUNCTION_TOKEN: me_token_unget(); return; case QUALIFIER_TOKEN: if (me_token_keyword() == keyword_done) { if (n) { sprintf(buf, "The average of your %d numbers is %.16g", n, sum / n); me_display_prompt(buf); me_wait_for_ack(); } return; } me_token_error(); break; case NUMBER_TOKEN: sum += me_token_number(); n+ +; break; case NO_TOKEN: break; default: me_token_error(); break; } } /*---------------------------------------------------------------------------*/ void DllExport init_load_init() { me_new_function("AI_DEMO", ai_demo_fnc); keyword_done = me_new_qualifier("DONE"); }
Discussion of the example:
This example shows some aspects of writing action routines. It
shows two functions, an initialization routine which is
executed at system startup time, and the real action routine,
which is called by the system if the user enters the keyword
AI_DEMO
.
The purpose of the initialization routine is to define two new
keywords, the function keyword AI_DEMO
, and a qualifier keyword
DONE
. The keyword pointer returned by me_new_qualifier()
is
remembered in a static variable, so that the action routine can
later check if this keyword was entered.
The action routine itself consists of one endless loop. On top
of the loop me_token_get()
is used to prompt the user to enter
either a number or the keyword DONE. Then the token type returned
by me_token_get()
is used in a switch statement to execute one of
several actions depending on the token type.
case COMMAND_TOKEN
:
case FUNCTION_TOKEN
:
The user has requested to abort this action routine and to start another one. Therefore the token just read (the command or function) is returned to the system and the action routine is left.
case QUALIFIER_TOKEN
:
The keyword pointer of the qualifier is retrieved and
compared to see if it is the qualifier DONE
. If yes,
the real action of the action routine will be taken.
The result is then
presented to the user until he/she presses any key to leave the
routine.
case NUMBER_TOKEN
:
The numeric value of the number token is retrieved and processed.
case NO_TOKEN
:
As me_token_get()
does not return a token, there is nothing
for the routine to do, so it loops to reissue the input request to the user.
default:
If the user has entered a token that the action routine cannot handle, it calls the general error routine and then loops to reissue the input request to the user.
A macro is a named list of one or more tokens. Whenever the user types a macro name in response to an input request from an action routine, this macro name is substituted with its associated token list, and the individual tokens are then presented to the action routine.
Macro names start with an uppercase letter optionally followed by lowercase letters, digits, or the _ character.
The following is a description of routines useful for building the pieces from which macros can be made.
struct keyword *me_search_keyword(name)
char *name;
This routine finds the keyword pointer of the keyword name. It
returns NULL
if the keyword is not defined.
struct macro *me_search_macro(name)
char *name;
This routine finds the macro pointer of the named macro. The macro is created if it does not exist already.
struct token *me_append_token(tokenlist, type, valueptr)
struct token *tokenlist;
int type;
void *valueptr;
This routine creates a new token of the specified type and appends it at the end of the specified token list. It returns the updated pointer to the head of the token list.
The following describes the types of tokens that may be created
and the value of valueptr
:
COMMAND_TOKEN
FUNCTION_TOKEN
QUALIFIER_TOKEN
ARITHM_FUNCTION_TOKEN
valueptr
has to be the address of the keyword pointer
SYMBOL_TOKEN | valueptr has to be the address of an integer describing the
symbol type
|
MACRO_TOKEN | valueptr has to be the address of the macro pointer
|
STRING_TOKEN | valueptr has to be the address of a C string
|
NUMBER_TOKEN | valueptr has to be the address of a double
precision number (type float64 )
|
POINT_TOKEN | valueptr has to be the address of a 2-dimensional
point (type struct fvec2 )
|
POINT_3D_TOKEN | valueptr has to be the address of a-3 dimensional
point (type struct fvec3 )
|
void me_create_macro(name, tokenlist
)
char *name
;
struct token *tokenlist
;
This associates the given token list with the macro name.
After this a macro is defined.
This will create the named macro and associate it with the given
tokenlist. If a macro with the same name already existed, it will
be deleted. This routine may also be used to delete a macro if
tokenlist
is a NULL
pointer.
Examples:
The following examples show both the interactive way to define macros and the programmatic approach. In each example you will see first the interactive definition (which is shorter). The benefit of the C-written solution is that it executes with higher performance.
Example 1
Macro: LET X1 12.5
C program:
double x1
;
x1 = 12.5
;
me_create_macro("X1", me_append_token(0, NUMBER_TOKEN, &x1));
Example 2
Macro: LET Mymacro 'Hello, world
'
C program:
me_create_macro("Mymacro",me_append_token(0, STRING_TOKEN, "Hello, world"));
In this example, the token list initially is zero.
Example 3
Macro:
DEFINE Makeit LINE 0,0 P1 DIM_LINE 0,0 P1 P2 END_DEFINE
C program:
struct fvec2 zero_point; struct keyword *keyword_line; struct keyword *keyword_dim_line; struct macro *macro_p1; struct macro *macro_p2; struct token *tokenlist; zero_point.x = zero_point.y = 0.0; keyword_line = me_search_keyword("LINE"); keyword_dim_line = me_search_keyword("DIM_LINE"); macro_p1 = me_search_macro("P1"); macro_p2 = me_search_macro("P2"); tokenlist = (struct token *) 0; tokenlist = me_append_token(tokenlist, COMMAND_TOKEN, &keyword_line); tokenlist = me_append_token(tokenlist, POINT_TOKEN, &zero_point); tokenlist = me_append_token(tokenlist, MACRO_TOKEN, ¯o_p1); tokenlist = me_append_token(tokenlist, COMMAND_TOKEN, &keyword_dim_line); tokenlist = me_append_token(tokenlist, POINT_TOKEN, &zero_point); tokenlist = me_append_token(tokenlist, MACRO_TOKEN, ¯o_p1); tokenlist = me_append_token(tokenlist, MACRO_TOKEN, ¯o_p2); me_create_macro("Makeit", tokenlist);
The following examples show how an arithmetic function computes the area of a circle and how a command reads and writes a macro variable.
Example 1
This arithmetic function computes the area of a circle. You can pass parameters to the arithmetic function.
#include <math.h> #include <stdio.h> #include <setjmp.h> #include "frame.h" #include "model2d.h" static struct token *circle_area() { float64 radius = 0.0; struct token *token; token = me_eval_factor(); if (me_type_of_token(token) == NUMBER_TOKEN) { radius = me_number_of_token(token); radius = radius * radius * me_pi; } free(token); return me_append_token(NULL, NUMBER_TOKEN, } void init_load_init() { me_new_arithm_function("CIRCLE_AREA", circle_area); }Windows-Based Systems: Replace
void init_load_init()
with void DllExport init_load_init()
.
Example 2
This command reads a macro variable. This is necessary if you want to inquire a macro variable within an AI program.
#include <math.h> #include <stdio.h> #include <setjmp.h> #include "frame.h" #include "model2d.h" static void read_macro() { float64 n = 0.0; char *message; char variable[1024]; struct token *token; struct macro *macro; message = "Enter a macro variable"; if (me_token_get(message) == STRING_TOKEN) { strcpy(variable, me_token_string()); macro = me_search_macro(variable); if (macro) { token = me_get_tokenlist_of_macro(macro); if (token & me_type_of_token(token) == NUMBER_TOKEN) { n = me_number_of_token(token); sprintf(variable, "%.15g", n); me_display_prompt(variable); me_wait_for_ack(); } } } } void init_load_init() { me_new_command("READ_MACRO", read_macro); }Windows-Based Systems: Replace
void init_load_init()
with void DllExport init_load_init()
.
Example 3
This command writes a macro variable. This is necessary if you want to overwrite a macro variable within an AI program
#include <math.h> #include <stdio.h> #include <setjmp.h> #include "frame.h" #include "model2d.h" static void write_macro() { float64 n = 0.0; char *message; char variable[1024]; struct token *token; struct macro *macro; message = "Enter a global variable"; if (me_token_get(message) == STRING_TOKEN) { strcpy(variable, me_token_string()); macro = me_search_macro(variable); if (macro) { token = me_get_tokenlist_of_macro(macro); if (token & me_type_of_token(token) == NUMBER_TOKEN) { message = "Enter new value"; if (me_token_get(message) == NUMBER_TOKEN) { n = me_token_number(); me_set_number_of_token(token, n); } } } } } void init_load_init() { me_new_command("WRITE_MACRO", write_macro); }Windows-Based Systems: Replace
void init_load_init()
with void DllExport init_load_init()
.
The ME10 AI system is composed of ONE relocatable, pre-linked object code module and several header files which reflect the interface to the sub-modules of the code file.
The ME10 AI product contains the following files:
me10f.lib
| Import library file |
frame.h
| Frame AI headers |
model2d.h
| 2D AI headers |
examples\*
| Application Module C-program Examples |
examples\makefile
| Makefile for complete application linking |
pers
| ME10F + user interface macros |
UNIX-Based Systems only:
The ME10 object modules operate together with the personality
files (for example, language files *.ms
) at run time. This
means that there is a complete set of ME10 personality files
required to run the ME10 AI version.
There are different requirements for integrating a specific application program into ME10. There are questions like "How do I, as an application integrator, offer the application code to the end user?" - OR- "What's the mechanism to activate the application module at the customer's site ?" -OR- "How independent is my application program code from ME10 code ?"
One goal is to offer a mechanism that provides the highest possible degree of flexibility and independence from the ME10 system revisioning process. This goal is reached as follows:
Here we have to distinguish two different phases:
During the development phase, there is the requirement to do debugging
on the code to be developed.
This is possible when the ME10 code is completely linked.
The function main()
within ME10 is always compiled with debug mode which
assures that the completely linked AI application code can be debugged if
specified in the appropriate makefile.
In this phase the developed code is assumed to be stable (debugged and tested) and it is possible to integrate the application code into ME10 at runtime of ME10. This process is called Dynamic linking at run time or for short Dynamic link.
The complete link process typically will be used during the development phase of the application.
The process of linking the different relocatable object code files within a makefile results in a completely linked executable code. This is called Complete link.
In the example, the ai_demo.o
module is linked together with,
for example, me10ai.o
, and the resulting executable is mexx
.
mexx
is ready to run.
Within the frame module there is one complete integration hook provided which represents the interface between the CAD system ME10 AND the application module(s) to be integrated.
All the commands, functions, and keywords will be made known to the ME10 system by means of this hook.
The command syntax at the ME10 user interface/macro level is
LOAD_MODULE "AI"
.
The module name "AI"
is a reserved name.
The corresponding C function activated by this ME10 LOAD_MODULE
"AI"
function is ai_initialize
This function ai_initialize
has to be provided once within the
application program.
The function syntax is as follows:
void ai_initialize() { static int initialized; if (initialized+ +) return; /* inform ME10 about new functions just once*/ /* specify here all newly to be defined Keywords, Commands and Functions */ /* the following is an example, see ai_demo.c example file */ me_new_function("AI_DEMO", ai_demo_fnc); keyword_done = me_new_qualifier("DONE"); }
The command syntax of the hook at ME10 user interface/macro level is
LOAD_MODULE
"Application_module_name.sl"
The Application_module_name.sl
is the relocatable object file to be linked.
The Application_module_name
can be determined by the AI-application-integrator.
The ME10 system architecture supports the dynamic loading on the
Series 700 with the following specifications:
The corresponding C function activated by this LOAD_MODULE
statement
is init_load_init
This function init_load_init
has to be provided once within the
application module to be linked.
The function syntax is as follows:
void init_load_init() { /* provide here ALL functions, commands, keywords which will be made known to the system ; an example is: */ me_new_function("TEST", test_fnc); }
Dynamic linking requires special understanding of some system boundary conditions. One is to satisfy all unresolved references out of libraries.
Typically ME10 has linked-in information which shared libraries are
required.
Very special library functionality, which an application might require in
order to load and run without problems, should be linked in the relocatable
dynamic loadable application.sl
file. The application module must not be linked
together directly with libraries. All libraries already contained in me10ai.o
.
are accessible for the AI application without additional linking.
However, if you get error messages after
LOAD_MODULE "xxxx.sl"concerning unresolved external references in your AI application module, then go through the following steps.
ld -b -o application.sl application.o
).
The command syntax of the hook at ME10 user interface/macro level is
LOAD_MODULE "Application_module_name.dll"
The Application_module_name.dll
is the dynamic-link library (DLL) to be
linked.)
The Application_module_name
can be determined by the AI-application-integrator.
On PC-based systems, the ME10 system architecture supports run-time dynamic
linking.
Application_module_name.dll
contains the overall functionality
for the complete application
The corresponding C function activated by this LOAD_MODULE
statement
is init_load_init
This function init_load_init
has to be provided once within the
application module to be linked.
The declaration DllExport
declares the function for export in
the DLL. Alternately, it may be declared during the linking of the DLL.
The function syntax is as follows:
void DllExport init_load_init() { /* provide here ALL functions, commands, keywords which will be made known to the system ; an example is: */ me_new_function("TEST", test_fnc); }
To write, compile, and link a new application module, the AI integrator has to go through the following steps.
(UNIX-Based Systems: Here it's assumed that during the AI application development the complete link facility is used. Later when the code is thoroughly tested and quality assured the dynamic link facility will be applied and tested).
ai_initialize
)
(Windows-Based Systems: init_load_init
)
which contains the keywords and action routine functions (commands,
functions).
ME_TRY, ME_RECOVER
)
in order to prevent abnormal system exceptions or terminations.
mexx.
LOAD_MODULE "AI"
into the
ME10 startup macro.
mexx.dll
LOAD_MODULE "mexx.dll"
into the
ME10 startup macro.
ai_initialize
by init_load_init
and replace LOAD_MODULE "AI"
by LOAD_MODULE "Application_name.sl",
filling
in the appropriate module name)
Set up a new makefile and generate a relocatable Application_name.sl
file.
LOAD_MODULE "Application_name.sl"
LOAD_MODULE "Application_name.dll"
init_load_init
is called during the LOAD_MODULE
command.
This makes it impossible to set break points in init_load_init
before it is
called.
To debug init_load_init
, use LOAD_MODULE CHECK "Application_name.dll"
instead.
ME10 will pause after loading the library but before calling
init_load_init
.
If your application uses the functions of the ME10 AI then your application program has to include the AI header files in the following order:
#include "frame.h" #include "model2d.h"
Be sure that the header file include
statements appear in the same order as
shown above.
Here are some hints in case something goes wrong during program development.
printf
statements, variable values and
fflush
's.
Example of the makefile on a Series 400 workstation:
CFLAGS = -g -I. -I/usr/include/X11R4 -I/usr/include/X11 \ -Aa -D_HPUX_SOURCE -Dhpux -Dhp9000s300 ME_MODULES = me10ai.o AI_MODULES = ai_demo.o LIBS = -L/usr/lib/X11R4\ -ldld\ -lXwindow \ -lsb \ -lXhp11 \ -lX11 \ -L/usr/PE/lib300 -lsi \ -iI077 -lF77 \ -lI77 \ -lm \ -ln mexx_deb: $(AI_MODULES) rm -f mexx cc -g -q -Wl,-E,-X 16000\ $(ME_MODULES)\ $(AI_MODULES) $(LIBS) /usr/lib/end.o mexx: $(AI_MODULES) rm -f mexx cc -g -q -Wl,-E,-X 16000\ $(ME_MODULES) $(AI_MODULES) $(LIBS)\ -o mexx ai_demo.o: ai_demo.c cc -c $(CFLAGS) -o ai_demo.o ai_demo.c
Example of the makefile for Microsoft® Visual C++® Version 1.0:
CC = cl CFLAGS = /nologo /Zi /D _DEBUG /D __WinNT /D DYN /D WANT_PROTOTYPES LFLAGS = /nologo /DEBUG:FULL /DEBUGTYPE:cv ..\me10f.lib AI_HEADER = ..\frame.h ..\model2d.h ai_demo.dll: ai_demo.obj link $(LFLAGS) ai_demo.obj -DLL -OUT:ai_demo.dll ai_demo.obj: ai_demo.c $(AI_HEADER) $(CC) $(CFLAGS) /c ai_demo.c
The command syntax of the hook at ME10 user interface/macro level
is UNLOAD_MODULE
"Application_module_name.sl".
The Application_module_name.sl
is the relocatable object file to be
unlinked. The Application_module_name
can be determined by the
AI-application-integrator. The ME10 system architecture
supports the dynamic unloading on the Series 700
with the following specifications:
The corresponding C function activated by this UNLOAD_MODULE
statement is init_unload_init
.
This function init_unload_init
has to be provided once within the
application module to be unlinked.
The function syntax is as follows:
int init_unload_init(int *mode, char **product_name, char **partner_key, char **product_key, void *dummy)
If Application_module_name.sl
wants to be unloaded this function has
to return 1. Otherwise the unlink will be aborted.
The parameters have the following meaning:
mode must be set to 1 product_name see ME-LS Access Kit, me_access_license_server() partner_key see ME-LS Access Kit, me_access_license_server() product_key see ME-LS Access Kit, me_access_license_server() dummy for future use
Example:
int init_unload_init(int *mode, char **product_name, char **partner_key, char **product_key, void *dummy) { /*** [1] free all dynamic data ***/ /*** [2] unsubscribe from all events ***/ /*** [3] supply return values ***/ *mode = 1; *product_name = "My_application_1"; *partner_key = "1Partnr1"; *product_key = "1Prodct1"; /*** [4] all ok for unload ***/ return 1; }
All functions and commands of the loadmodule will automatically be
disabled during the unlink. Finally, the system releases the license
that has been granted to the loadmodule before with a call of
me_access_license_server()
(see ME-LS Access Kit) and removes the
loadmodule from the memory.
The command syntax of the hook at ME10 user interface/macro level
is UNLOAD_MODULE
"Application_module_name.dll".
The Application_module_name.dll
is the relocatable object file to be
unlinked. The Application_module_name
can be determined by the
AI-application-integrator. The ME10 system architecture
supports the dynamic unloading on PC-based systems with the following
specification:
The corresponding C function activated by this UNLOAD_MODULE
statement is init_unload_init
.
This function init_unload_init
has to be provided once within the
application module to be unlinked.
The function syntax is as follows:
int DllExport init_unload_init(int *mode, char **product_name, char **partner_key, char **product_key, void *dummy)
If Application_module_name.dll
wants to be unloaded this function has
to return 1. Otherwise the unlink will be aborted.
The parameters have the following meaning:
mode must be set to 1 product_name see ME-LS Access Kit, me_access_license_server() partner_key see ME-LS Access Kit, me_access_license_server() product_key see ME-LS Access Kit, me_access_license_server() dummy for future use
Example:
int DllExport init_unload_init(int *mode, char **product_name, char **partner_key, char **product_key, void *dummy) { /*** [1] free all dynamic data ***/ /*** [2] unsubscribe from all events ***/ /*** [3] supply return values ***/ *mode = 1; *product_name = "My_application_1"; *partner_key = "1Partnr1"; *product_key = "1Prodct1"; /*** [4] all ok for unload ***/ return 1; }
All functions and commands of the loadmodule will automatically be
disabled during the unlink. Finally, the system releases the license
that has been granted to the loadmodule before with a call of
me_access_license_server()
(see ME-LS Access Kit) and removes the
loadmodule from the memory.
There is a function that provides the ME10 revision control string and the ME10 product name. This facility enables the application writer to check if the application fits together with a given ME10 revision at the customer's site.
me_version_control
)
What is Feedback from a user's point of view?
It is a graphical support tool for interactive user input either by a mouse or tablet.
Feedback is all that can be dynamically or statically attached temporarily, for example, to the cursor while setting up or modifying the CAD model interactively.
What is Feedback from an internal system point of view?
Feedback consists of a model containing the graphical data and a procedure that updates the graphical model and draws it on the screen. Feedback model is directly dependent on an action routine. It exists as long as an action routine is active, which means it is owned by an action routine.
Whenever an action routine awaits user input and the cursor steered by the graphic input device changes its position, the feedback update procedure is called with the name of the feedback model of the cursor position as a parameter.
The name of this graphic model is "me_cursor_fdbck_model"
.
A feedback model consists of an ordered list of sub-models.
An action routine can create feedback sub-models, which are active when
the action routine is active. Feedback sub_models
, when active,
are drawn on the screen and updated.
They are inactive, when the action routine
is interrupted by another action routine. They are automatically
deleted, when the action routine is terminated.
The components of a feedback sub-model are :
me_end_add_fdbck_to_model
)
The viewport lists specify in which viewports the submodel is to be drawn. There are predefined feedback viewport lists provided by the owners of the viewports, for example, viewports of the 2D model.
me_cursor_gport
)
me_cursor_fdbck_model
)
me_cursor_model_pnt
)
When a feedback sub-model is drawn on the screen and no model matrix has been specified for the sub-model, the model to screen coordinate mapping set by the owner of the viewport is used.
If the feedback sub-model needs to be specified in a coordinate system other than that set by the viewport owner, the model matrix of the sub-model must be defined. The model matrix is taken to be the transformation from the feedback sub-model to the coordinate system of the viewport owner.
The feedback points determine the movements of the graphical feedback sub-model. They can reference each other.
There are different types of feedback points :
Fixed points are independent of other feedback points and have a fixed postion on the screen.
Translation points reference two feedback points. Their x and y coordinates have a fixed distance from the x and y coordinates respectively of their reference points.
Rotation points reference three feedback points. The first is the center about which they rotate. The second and the third are the reference points, that determine respectively their polar coordinates r and phi relative to the first point. Coordinate transformation points are needed if a feedback point in another feedback sub-model with a different coordinate system is to be referenced. They perform a coordinate transformation.
There is a special predefined feedback point which represents the
cursor position on the screen. It is called "me_cursor_fdbck_pnt"
which provides the screen coordinates of the cursor position.
For routines, see FDBCKPNT in ME10 AI Reference.
Feedback elements join up feedback points. They are the visible elements on screen and reference feedback points.
Three types of feedback elements are supported:
There is a maximum complexity for a feedback model.
This maximum value can be specified interactively in ME10 with the
function called "max_feedback"
.
If this maximum value is reached by a feedback model, then
no further moving elements or points can
be added to a sub-model of "me_cursor_fdbck_model."
.
However, the feedback tree in "me_cursor_fdbck_model"
can still be accessed.
There is no AI routine available to adjust this value. It can be done via the Macro to AI communication.
me_end_add_fdbck_to_model
)
me_add_fdbck_fix_pnt
)
me_add_fdbck_rot_pnt
)
me_add_fdbck_line
)
me_add_fdbck_arc
)
me_add_fdbck_box
)
me_add_fdbck_parallelogram
)
me_del_fdbck_elements, me_del_all_fdbck_elements
)
me_del_last_fdbck_element
)
To support general geometrical calculations, the AI provides some basics for 3D vector and matrix algebra. The 2D modeler is treated as being 3D with the third component set to zero. (You, as a user of AI, should take care of this, especially if you handle 2-dimensional data. In this case the Z- coordinates should be consistently defined to be 3D compatible (Z coordinates should be pre-set to zero).
When using vector and matrix functions, the following boundary conditions should be kept in mind:
struct fvec3
with
struct fvec3 { float64 x, y, z; }
geo_operator_3
.
In the following, we will refer to this object as geo operator
.
malloc
.
me_resolution
if not defined otherwise in the function descriptions.
Vector algebra is one of the fundamental concepts for the 2D/3D functionality. For vector algebra functions, no distinction is made between points and vectors. Both have the same data structure, therefore they can be treated in the same manner. Thus, if we talk about a point, we mean a vector from the origin to that point.
Some often used vectors are already predefined:
me_add_vec_3
)
me_angle_between_vec_3
)
me_calc_orthogonal_vec_3
)
me_cmp_vec_3
)
me_euclidian_norm_3
)
me_inv_scale_vec_3
)
me_normalise_vec_3
)
me_outer_product_3
)
me_scalar_product_3
)
me_scale_vec_3
)
me_subtract_vec_3
)
me_map_pnt_to_plane_3
)
me_map_pnt_to_line
)
Matrices are part of geo operators which consist of:
The 4x4 matrix notation is a convenient way to deal with transformations of the type:
General Transformation
When a homogenous 4x4 matrix is used to transform a 3D vector, the vector is first converted into a homogenous vector, second multiplied with the 4x4 matrix, and third reconverted into a 3D vector. That is:
Mapping Homogenous Vectors
with
s' = p__1__x + p__2__y + p__3__z + s
The identity matrix is predefined and is denoted by the symbol
me_idn_operator
.
Predefined Identity Operator
me_analyse_geo_op_3
)
me_determinant_of_geo_op_3
)
me_cmp_geo_op_3
)
me_create_equal_scaling_3
)
me_create_geo_op_3
)
me_create_reflection_3
)
me_create_rotation_3
)
me_create_translation_3
)
me_inq_matrix_of_geo_op_3
)
me_inv_geo_op_3
)
me_multiply_geo_op_3
)
me_create_affine_transform_3
)
me_map_vec_3
)
To enable an AI application to know the revision of the AI product, a function is available to return the name and the revision of the AI product.
me_version_control
)