Как предотвратить освещение объекта в Matlab камуфляжем? - PullRequest
0 голосов
/ 19 декабря 2018

[Здесь и далее 4 фрагмента, нужно только прочитать два первых.Однако, скопировав все это, вы сможете запустить то, что я вижу, хотя скриншоты предоставляются в конце .]

Привет, запустив этот main.m :

%To see if plotting a tick after setting camlight headlight will leads to
%its background becoming gray or not
%clear all
figure
arrow = arrow3D([0 0 0], [1 1 1], 'r', 0.8, 0.2, 1.5);
set(arrow, 'EdgeColor', 'interp', 'FaceColor', 'interp');
%camlight headlight %might be interesting to uncomment this line
pause(5)
surfaceHandle = rotateAxisTicks('lol','r',10,-0.3,0.5,0.5,1,1,1,0);
pause(5)
camlight headlight
%material(surfaceHandle,'default') %doesn't work
%surfaceHandle1.FaceLighting = 'none' %doesn't work

, который использует эту функцию rotateAxisTicks.m

function surfaceHandle = rotateAxisTicks(str,color,fontsize,zmax,graduSpace,boxHeight,perc,labelNumber,axnumber,thetaInput)
%/5952468/matlab-kak-postroit-tekst-v-3d
    %zmax : give it a negative value to not overlap the axis
    %graduSpace : space between each graduation, within the projected on [0,1] axis if axis = x||y, OR local (not yet projected on x,y) axis !!
    %boxHeight : width of the boxes depend on how much the axis graduations are refined, so height shouldn't depend on graduSpace
    %perc : if perc = 1 (100%), then the labels are all sticked together with no space inbetween
    %labelNumber : the first tick to be displayed is actually associated to the second graduation (0 can't get several labels)
    %axnumber : out of nbParams, 1 for x, 2 for y, then, from closest to x, to closest to y : 3 to nbParams.
    %thetaInput : (angle around z, from x to the axis) has to be in degree

    %% Seems like there is no way to get rid of the black contouring...
    hFigure = figure(1000);
    set(hFigure,'Color', 'w', ...        % Create a figure window
                     'MenuBar', 'none', ...
                     'ToolBar', 'none');
    hText = uicontrol('Parent', hFigure, ...  % Create a text object
                      'Style', 'text', ...
                      'String', str, ...
                      'BackgroundColor', 'w', ...
                      'ForegroundColor', color, ...
                      'FontSize', fontsize, ...
                      'FontWeight', 'normal');
    set([hText hFigure], 'Pos', get(hText, 'Extent'));  %# Adjust the sizes of the
                                                        %#   text and figure
    imageData = getframe(hFigure);  %# Save the figure as an image frame
    delete(hFigure);
    textImage = imageData.cdata;  %# Get the RGB image of the text

    %% MAKE THE X,Y,Z (text) REVERSE DEPENDING ON AZIMUT VALUE (launch a fig and see on the bottom in real time the azimut value)
    % X or Y or Z(1,1) =  _______
    %                    *       |
    %                    |       |
    %                    |_______|
    % X or Y or Z(1,2) =  _______
    %                    |       *
    %                    |       |
    %                    |_______|
    % X or Y or Z(2,1) =  _______
    %                    |       |
    %                    |       |
    %                    x_______|
    % X or Y or Z(2,2) =  _______
    %                    |       |
    %                    |       |
    %                    |_______x
    if axnumber == 2 %axis = y
        X = [0 0; 0 0];
        Y = [0 perc*graduSpace; 0 perc*graduSpace] + labelNumber*graduSpace - perc*graduSpace/2;
        %(graduSpace/2)/2 to center under the graduation, (1-perc)/2) to
        %additionally shift a bit so that the perc% of graduSpace stay centered
        %under the graduation
    else %I assume axis = x, that I might later rotate if it's not actually x
        X = [0 perc*graduSpace; 0 perc*graduSpace] + labelNumber*graduSpace - perc*graduSpace/2; %+labelNumber*((graduSpace/2)+((1-perc)/2)*graduSpace)
        Y = [0 0; 0 0];
    end
    Z = [zmax zmax; zmax-boxHeight zmax-boxHeight];
    surfaceHandle = surf(X, Y, Z, 'FaceColor', 'texturemap', 'CData', textImage);
    if axnumber > 2
        rotate(surfaceHandle, [0 0 1], thetaInput,[0 0 0]);
    end
end

, а также эту функцию arrow3D.m :

function arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio, cylRad, radRatioCone)

% arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
%     Used to plot a single 3D arrow with a cylindrical stem and cone arrowhead
%     pos = [X,Y,Z] - spatial location of the starting point of the arrow (end of stem)
%     deltaValues = [QX,QY,QZ] - delta parameters denoting the magnitude of the arrow along the x,y,z-axes (relative to 'pos')
%     colorCode - Color parameters as per the 'surf' command.  For example, 'r', 'red', [1 0 0] are all examples of a red-colored arrow
%     stemRatio - The ratio of the length of the stem in proportion to the arrowhead.  For example, a call of:
%                 arrow3D([0,0,0], [100,0,0] , 'r', 0.82) will produce a red arrow of magnitude 100, with the arrowstem spanning a distance
%                 of 82 (note 0.82 ratio of length 100) while the arrowhead (cone) spans 18.  
% 
%     Example:
%       arrow3D([0,0,0], [4,3,7]);  %---- arrow with default parameters
%       axis equal;
% 
%    Author: Shawn Arseneau
%    Created: September 14, 2006
%    Updated: September 18, 2006
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if nargin<2 || nargin>6    
        error('Incorrect number of inputs to arrow3D');     
    end
    if numel(pos)~=3 || numel(deltaValues)~=3
        error('pos and/or deltaValues is incorrect dimensions (should be three)');
    end
    if nargin<3                 
        colorCode = 'interp';                               
    end
    if nargin<4                 
        stemRatio = 0.75;                                   
    end    

    X = pos(1); %---- with this notation, there is no need to transpose if the user has chosen a row vs col vector
    Y = pos(2);
    Z = pos(3);

    [sphi, stheta, srho] = cart2sph(deltaValues(1), deltaValues(2), deltaValues(3));  

    %******************************************* CYLINDER == STEM *********************************************
    %cylinderRadius = 0.05*srho;
    cylinderRadius = cylRad;
    cylinderLength = srho*stemRatio;
    [CX,CY,CZ] = cylinder(cylinderRadius);
    CZ = CZ.*cylinderLength;    %---- lengthen

    %----- ROTATE CYLINDER
    [row, col] = size(CX);      %---- initial rotation to coincide with X-axis

    newEll = rotatePoints([0 0 -1], [CX(:), CY(:), CZ(:)]); %CX(:) actually reshape the 2xN matrices in a 2N vert vector, by vertically concatenating each column
    CX = reshape(newEll(:,1), row, col);
    CY = reshape(newEll(:,2), row, col);
    CZ = reshape(newEll(:,3), row, col);

    [row, col] = size(CX);    
    newEll = rotatePoints(deltaValues, [CX(:), CY(:), CZ(:)]);
    stemX = reshape(newEll(:,1), row, col);
    stemY = reshape(newEll(:,2), row, col);
    stemZ = reshape(newEll(:,3), row, col);

    %----- TRANSLATE CYLINDER
    stemX = stemX + X;
    stemY = stemY + Y;
    stemZ = stemZ + Z;

    %******************************************* CONE == ARROWHEAD *********************************************
    coneLength = srho*(1-stemRatio);
    coneRadius = cylinderRadius*radRatioCone;
    incr = 100;  %---- Steps of cone increments
    coneincr = coneRadius/incr;
    [coneX, coneY, coneZ] = cylinder(cylinderRadius*2:-coneincr:0);  %---------- CONE 
    coneZ = coneZ.*coneLength;

    %----- ROTATE CONE 
    [row, col] = size(coneX);    
    newEll = rotatePoints([0 0 -1], [coneX(:), coneY(:), coneZ(:)]);
    coneX = reshape(newEll(:,1), row, col);
    coneY = reshape(newEll(:,2), row, col);
    coneZ = reshape(newEll(:,3), row, col);

    newEll = rotatePoints(deltaValues, [coneX(:), coneY(:), coneZ(:)]);
    headX = reshape(newEll(:,1), row, col);
    headY = reshape(newEll(:,2), row, col);
    headZ = reshape(newEll(:,3), row, col);

    %---- TRANSLATE CONE
    V = [0, 0, srho*stemRatio];    %---- centerline for cylinder: the multiplier is to set the cone 'on the rim' of the cylinder
    Vp = rotatePoints([0 0 -1], V);
    Vp = rotatePoints(deltaValues, Vp);
    headX = headX + Vp(1) + X;
    headY = headY + Vp(2) + Y;
    headZ = headZ + Vp(3) + Z;
    %************************************************************************************************************    
    hStem = surf(stemX, stemY, stemZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
    hold on
    hBottStem = fill3(stemX(1,:),stemY(1,:),stemZ(1,:), colorCode, 'EdgeColor', 'none');
    hold on
    hHead = surf(headX, headY, headZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
    hold on
    hBottCone = fill3(headX(1,:),headY(1,:),headZ(1,:), colorCode, 'EdgeColor', 'none');

    if nargout==1   
        arrowHandle = [hStem, hBottStem, hHead, hBottCone]; 
    end

, который сам использует эту функцию rotatePoints.m :

function rotatedData = rotatePoints(alignmentVector, originalData)

% rotatedData = rotatePoints(alignmentVector, originalData) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
%     Rotate the 'originalData' in the form of Nx2 or Nx3 about the origin by aligning the x-axis with the alignment vector
% 
%       Rdata = rotatePoints([1,2,-1], [Xpts(:), Ypts(:), Zpts(:)]) - rotate the (X,Y,Z)pts in 3D with respect to the vector [1,2,-1]
% 
%       Rotating using spherical components can be done by first converting using [dX,dY,dZ] = cart2sph(theta, phi, rho);  alignmentVector = [dX,dY,dZ];
% 
% Example:
%   %% Rotate the point [3,4,-7] with respect to the following:
%   %%%% Original associated vector is always [1,0,0]
%   %%%% Calculate the appropriate rotation requested with respect to the x-axis.  For example, if only a rotation about the z-axis is
%   %%%% sought, alignmentVector = [2,1,0] %% Note that the z-component is zero
%   rotData = rotatePoints(alignmentVector, [3,4,-7]);
% 
%     Author: Shawn Arseneau
%     Created: Feb.2, 2006
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    alignmentDim = numel(alignmentVector); %number of elements in a matrix
    DOF = size(originalData,2); %---- DOF = Degrees of Freedom (i.e. 2 for two dimensional and 3 for three dimensional data)

    if alignmentDim~=DOF    
        error('Alignment vector does not agree with originalData dimensions');      
    end
    if DOF<2 || DOF>3      
        error('rotatePoints only does rotation in two or three dimensions');        
    end


    if DOF==2  % 2D rotation...        
        [rad_theta, rho] = cart2pol(alignmentVector(1), alignmentVector(2));    
        deg_theta = -1 * rad_theta * (180/pi);
        ctheta = cosd(deg_theta);  stheta = sind(deg_theta);

        Rmatrix = [ctheta, -1.*stheta;...
                   stheta,     ctheta];
        rotatedData = originalData*Rmatrix; 
        %assumption: rotate all the datas from the original base to the
        %base where the original x becomes alignmentVector

    else    % 3D rotation...        
        [rad_theta, rad_phi, rho] = cart2sph(alignmentVector(1), alignmentVector(2), alignmentVector(3));
        rad_theta = rad_theta * -1; 
        deg_theta = rad_theta * (180/pi);
        deg_phi = rad_phi * (180/pi); 
        ctheta = cosd(deg_theta);  stheta = sind(deg_theta); %MM : is it more accurate??
        Rz = [ctheta,   -1.*stheta,     0;...
              stheta,       ctheta,     0;...
              0,                 0,     1];                  %% First rotate as per theta around the Z axis
        rotatedData = originalData*Rz;

        [rotX, rotY, rotZ] = sph2cart(-1* (rad_theta+(pi/2)), 0, 1);          %% Second rotation corresponding to phi
        %assuming alignmentVector is the x for the new base, then the
        %hereabove argument corresponds to the y (z inversed)
        %the hereabove output = newX(in base 0) vectorial product -z(in base0)
        rotationAxis = [rotX, rotY, rotZ];
        u = rotationAxis(:)/norm(rotationAxis);        %% Code extract from rotate.m from MATLAB
        cosPhi = cosd(deg_phi);
        sinPhi = sind(deg_phi);
        invCosPhi = 1 - cosPhi;
        x = u(1);
        y = u(2);
        z = u(3);
        Rmatrix = [cosPhi+x^2*invCosPhi        x*y*invCosPhi-z*sinPhi     x*z*invCosPhi+y*sinPhi; ...
                   x*y*invCosPhi+z*sinPhi      cosPhi+y^2*invCosPhi       y*z*invCosPhi-x*sinPhi; ...
                   x*z*invCosPhi-y*sinPhi      y*z*invCosPhi+x*sinPhi     cosPhi+z^2*invCosPhi]';

        rotatedData = rotatedData*Rmatrix;        
    end

Я получаю: that ugly plot

, в то время как я хотел бы сохранить оба промежуточных графика, содержащие стрелку interp: the interp arrow

и текст на ярком белом фоне: the text on flashy white background

Таким образом, на самом деле есть два вопроса:

1) Почему при вызове моего текстового тика отключается эффект взаимодействия (цвет меняется от синего до желтого))?

2) Как я могу сохранить лампу, не освещая мой флажок?(т. е. сохраняя белый фон)

По сути, нужно смотреть только на два первых фрагмента, а два последующих бесполезны для моей проблемы.

Благодарю васмного!

1 Ответ

0 голосов
/ 20 декабря 2018

Поместите его в другое axes

Как я уже сказал в комментарии, у вас есть 2 графических объекта в одном и том же axes, которые должны интерпретировать их CData совершенно по-другому.

Первым вариантом, который я искал, было изменение одного из arrow3d или rotateAxisTicks, чтобы их графические объекты были «совместимы» (в том смысле, как данные цвета интерполируются по осям), но это было бы довольноинтенсивный и аспект трехмерного текста должен был бы постоянно контролироваться / корректироваться для любого другого изменения в рисунке.

Таким образом, самый простой вариант - классический взлом MATLAB ... поместите ваши графические объекты в различные контейнеры (другой axes), затем накладывает их на фигуру и сопоставляет некоторые свойства (пределы, вид и т. д.), чтобы они казались только одним.

Вот так:

%% Draw your main arrow in the main figure
mainfig = figure ;
ax1     = axes ;
arrow = arrow3D([0 0 0], [1 1 1], 'r', 0.8, 0.2, 1.5);
set(arrow, 'EdgeColor', 'interp', 'FaceColor', 'interp');
camlight headlight

%% Draw your text in a temporary figure
tempfig = figure ;
ax2 = axes ;
surfaceHandle = rotateAxisTicks('lol','r',10,-0.3,0.5,0.5,1,1,1,0);
camlight headlight
%material(surfaceHandle,'default') %doesn't work
%surfaceHandle1.FaceLighting = 'none' %doesn't work

%% Prepare and set matching limits
xl = [ax1.XLim ; ax2.XLim] ;
xl = [min(xl(:,1)) , max(xl(:,2))] ;
yl = [ax1.YLim ; ax2.YLim] ;
yl = [min(yl(:,1)) , max(yl(:,2))] ;
zl = [ax1.ZLim ; ax2.ZLim] ;
zl = [min(zl(:,1)) , max(zl(:,2))] ;

hax = [ax1;ax2] ;
set(hax,'XLim',xl,'YLim',yl,'ZLim',zl)

% Adjust the view to be sure
ax2.View = ax1.View ;

%% Remove secondary axes background, then move it to main figure
ax2.Visible = 'off' ;   
ax2.Parent = mainfig ;
delete(tempfig)

%% link the view between axes
hl = linkprop( hax , 'View' ) ;
% or link even more properties at once
% hl = linkprop( hax , 'View' , 'XLim','YLim','ZLim') ;

Что дает вам:

3d arrow


примечание : ваша 3d-стрелка также состоит из 2 различныхграфические объекты (2x surf и 2x patch).2 патча не отображаются при установке режима interp.Вам следует изменить функцию arrow3d, чтобы (а) изменить объекты patch на surf, чтобы все были одного типа и были совместимы, или (б) полностью удалить их из функции (если они не отображаются, онитолько раздражает ... вызывает повсюду предупреждения).


edit

А вот модифицированный код для arrow3d.m.Я изменил его, так что теперь выводом является только один поверхностный объект, проще назначать свойства и нет опасности несоответствия между patch и surf.Я также упростил его, удалил несколько ненужных битов и уменьшил общее количество точек, необходимых для поверхности.

При этом вы получите нижнюю часть стебля и нижний конус:

function arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio, cylRad )

% arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
%     Used to plot a single 3D arrow with a cylindrical stem and cone arrowhead
%     pos = [X,Y,Z] - spatial location of the starting point of the arrow (end of stem)
%     deltaValues = [QX,QY,QZ] - delta parameters denoting the magnitude of the arrow along the x,y,z-axes (relative to 'pos')
%     colorCode - Color parameters as per the 'surf' command.  For example, 'r', 'red', [1 0 0] are all examples of a red-colored arrow
%     stemRatio - The ratio of the length of the stem in proportion to the arrowhead.  For example, a call of:
%                 arrow3D([0,0,0], [100,0,0] , 'r', 0.82) will produce a red arrow of magnitude 100, with the arrowstem spanning a distance
%                 of 82 (note 0.82 ratio of length 100) while the arrowhead (cone) spans 18.  
% 
%     Example:
%       arrow3D([0,0,0], [4,3,7]);  %---- arrow with default parameters
%       axis equal;
% 
%    Author: Shawn Arseneau
%    Created: September 14, 2006
%    Updated: September 18, 2006
%
%    Updated: December 20, 2018
%       Tlab - refactored to have only one surface object as ouput
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if nargin<2 || nargin>6    
        error('Incorrect number of inputs to arrow3D');     
    end
    if numel(pos)~=3 || numel(deltaValues)~=3
        error('pos and/or deltaValues is incorrect dimensions (should be three)');
    end
    if nargin<3                 
        colorCode = 'interp';                               
    end
    if nargin<4                 
        stemRatio = 0.75;                                   
    end    
    Ncol = 21 ; % default number of column for the "cylinder.m" function

    X = pos(1); %---- with this notation, there is no need to transpose if the user has chosen a row vs col vector
    Y = pos(2);
    Z = pos(3);

    [~, ~, srho] = cart2sph(deltaValues(1), deltaValues(2), deltaValues(3));  

    %******************************************* CYLINDER == STEM *********************************************
    cylinderRadius = cylRad;
    cylinderLength = srho*stemRatio;
    [CX,CY,CZ] = cylinder(cylinderRadius,Ncol-1);
    CZ = CZ.*cylinderLength;    %---- lengthen

     %******************************************* CONE == ARROWHEAD *********************************************
    coneLength = srho*(1-stemRatio);
    [coneX, coneY, coneZ] = cylinder([cylinderRadius*2 0],Ncol-1);  %---------- CONE 
    coneZ = coneZ.*coneLength;
    % Translate cone on top of the stem cylinder
    coneZ = coneZ + cylinderLength ;

    % now close the bottom and add the cone to the stem cylinder surface
    bottom = zeros(1,Ncol) ;
    CX = [ bottom ; CX ; coneX ] ;
    CY = [ bottom ; CY ; coneY ] ;
    CZ = [ bottom ; CZ ; coneZ ] ;

    Nrow = size(CX,1);


    %----- ROTATE
    %---- initial rotation to coincide with X-axis
    newEll = rotatePoints([0 0 -1], [CX(:), CY(:), CZ(:)]); %CX(:) actually reshape the 2xN matrices in a 2N vert vector, by vertically concatenating each column
    CX = reshape(newEll(:,1), Nrow, Ncol);
    CY = reshape(newEll(:,2), Nrow, Ncol);
    CZ = reshape(newEll(:,3), Nrow, Ncol);

    newEll = rotatePoints(deltaValues, [CX(:), CY(:), CZ(:)]);
    stemX = reshape(newEll(:,1), Nrow, Ncol);
    stemY = reshape(newEll(:,2), Nrow, Ncol);
    stemZ = reshape(newEll(:,3), Nrow, Ncol);

    %----- TRANSLATE
    stemX = stemX + X;
    stemY = stemY + Y;
    stemZ = stemZ + Z;

    %----- DISPLAY
    hStem = surf(stemX, stemY, stemZ, 'FaceColor', colorCode, 'EdgeColor', 'none');

    %----- DISPLAY
    if nargout==1   
        arrowHandle = hStem ; 
    end
...