Array of an array of a graphics object in a built-in matlab function in Simulink in R2014a or newer

For debugging, I have some vector plots in the built-in matlab function in Simulink. Before Matlab R2013b everything works fine with the following minimal code example:

function fcn
%#minimum example for plot within for-loop of embedded matlab function

coder.extrinsic('delete');
coder.extrinsic('quiver');
coder.extrinsic('gobjects');
numSteps=4;

persistent hFig;
persistent hVector;

if isempty(hFig)
    hFig = figure;
    hold on;
    hVector=zeros(numSteps,1);
    hVector=gobjects(numSteps,1);
    for i=1:numSteps
        hVector(i) = quiver(0,0,0,0);
    end
end
set(0, 'CurrentFigure', hFig);
delete(hVector);
for i=1:numSteps
    startInc=[1 1;1 1].*i;
    endInc=[2 3;2 -3].*i;
    hVector(i) = quiver(startInc(1,:),startInc(2,:),endInc(1,:),endInc(2,:));
end

      

The descriptor array hVector

needs initialization due to its use in for

-loop. However, to initialize the object of the graphic descriptor, a function is needed gobjects

and, in turn, it becomes necessary to initialize as a double c zeros(numSteps,1)

, since Matlab cannot correctly determine the data type of the output of the external function. As I said, this piece of code works great if copied into the matlab inline function block in simulink without any changes to the model.

My problem: Mathworks changed many build functions in R2014a, one of the changes is the datatype of the graphics handles, which are not of type quiver

for my quiver site. Therefore, initialization with zeros(numSteps,1)

initializes the wrong data type for the descriptor array. However, leaving it still doesn't work, due to the problem mentioned above. Neither init loop nor anything like that compiles without error.

I would really appreciate any help on this issue.

+3


source to share


1 answer


You can try to remove the initialization gobject

and use double()

to bind your call to any matlab graphics object. Example:

hVector(i) = double( quiver(startInc(1,:),startInc(2,:),endInc(1,:),endInc(2,:)) ) ;

      

I suggest reading Loren 's article on compatibility issues that can arise when switching to HG2 versions of Matlab.

A quick quote from her that deals more with your problem:

Graphical Functions Returned Objects, Not Numeric Pens

Before R2014b, you can store a set of descriptors for graphic objects in an array and then add some numeric data to that array. In R2014b, which will result in an error.
[...]
If you are really stuck, you can use an object that handles numeric descriptors using a function double

. Then you can return the number to the object descriptor using a function handle

. We do not recommend this as a long term solution. Remember that we may choose this function in a future version of MATLAB. If we do, we will inform you in advance.


Now, if you really need to use this solution, please note that both functions work on both single elements and arrays. So

hVector_HG  = handle( hVector_Num ) ; %// works if "hVector_Num" is an array of numeric handles
%// and ...
hVector_Num = double( hVector_HG ) ;  %// works if "hVector_HG" is an array of HG2 graphic handles

      

This can facilitate round trips between format or another if they become necessary frequently.


Edit:



I am putting this at the bottom of the post for now because the start is already accepted, but try the following and let me know if it works. It can solve your problem in a better (more reliable future) way.

Another way to initialize the handle array of a given graphic is to create one (empty is enough) and replicate it. For example:

hqNaN   = quiver(NaN,NaN) ;                 %// create an empty quiver
hVector = repmat( hqNaN , numSteps , 1 ) ;  %// replicate it in an array

      

will give you an array hVector

containing numSteps

HG2 graphics. At this point they are all pointing to the same object, but it is perfectly legal to overwrite each element with a descriptor of the same type. So later:

hVector(i) = quiver( ... , etc ... ) ; %// overwrite handle "i" with a new quiver plot handle

      

will (should) work without problems.

A few things to take care of this:

  • where will the empty quiver be created?
    you may already have a "current" shape and do not want to be confused. Unless a new empty plot is created. So to make sure that an empty quiver isn't causing problems (just flickering on the screen), you can wrap it like this:

    figure ; hqNaN = quiver(NaN,NaN) ; close(gcf) ;

or you can also park it on the figure (it will be invisible anyway) in case you need to reuse a descriptor of that type for another array initialization. Just remember that after you close the shape that it is enabled on, or you delete the graphic object, the variable hqNaN

still exists, but it is no longer the same descriptor type (so it is not advisable to copy if you want this type exactly ).

  • What if you don't overwrite all the initial descriptor arrays?
    Remember that all the initial array descriptors point to the same graphics object. Therefore, if your array contains 12 elements, but suppose by mistake you only overwrite 10 of them, then 2 elements will process pointers to the same object (which you may have already deleted)). This means calling:
    delete(hVector)


    will annoy you:
    Error using handle.handle/delete. Invalid or deleted object.


    gna gna gna ... luckily you can easily prepare for this by programming defensively and using instead:
    delete( hVector(ishandle(hVector)) )


    Matlab will automatically check and remove only the correct handles.
+3


source







All Articles