1

I have created a 3D truncated icosahedron in matlab using the patch function. I would like to add images to each of the faces.

Apparently this is not possible using patch, but only using surf. Unfortunately it is not possible to use surf in this case, since the surfaces created using it always have a square as a base.

Is there any way to add an image to the sides of a 3D polygon in Matlab?

s = 0.5;
s1 = s/3;
s2 = s * 2/3;
h =s*0.5*(sqrt(5)-1);
h1=h/3;
h2=h*2/3;
k1=h+(s-h)/3;
k2=h+(s-h)*2/3;

V1_1=-s; V2_1=0; V3_1=h1;
V1_2=-s; V2_2=0; V3_2=-h1;
V1_3=-k2; V2_3=s1; V3_3=-h2;
V1_4=-k1; V2_4=s2; V3_4=-h1;
V1_5=-k1; V2_5=s2; V3_5=h1;
V1_6=-k2; V2_6=s1; V3_6=h2;
V1_7=-k2; V2_7=-s1; V3_7=-h2;
V1_8=-k1; V2_8=-s2; V3_8=-h1;
V1_9=-k1; V2_9=-s2; V3_9=h1;
V1_10=-k2; V2_10=-s1; V3_10=h2;
V1_11=-s2; V2_11=-h1; V3_11=k1;
V1_12=-s1; V2_12=-h2; V3_12=k2;
V1_13=0; V2_13=-h1; V3_13=s;
V1_14=0; V2_14=h1; V3_14=s;
V1_15=-s1; V2_15=h2; V3_15=k2;
V1_16=-s2; V2_16=h1; V3_16=k1;
V1_17=-h1; V2_17=k1; V3_17=s2;
V1_18=-h2; V2_18=k2; V3_18=s1;
V1_19=-h2; V2_19=-k2; V3_19=s1;
V1_20=-h1; V2_20=-k1; V3_20=s2;
V1_21=s; V2_21=0; V3_21=-h1;
V1_22=s; V2_22=0; V3_22=h1;
V1_23=k2; V2_23=-s1; V3_23=h2;
V1_24=k1; V2_24=-s2; V3_24=h1;
V1_25=k1; V2_25=-s2; V3_25=-h1;
V1_26=k2; V2_26=-s1; V3_26=-h2;
V1_27=k2; V2_27=s1; V3_27=h2;
V1_28=k1; V2_28=s2; V3_28=h1;
V1_29=k1; V2_29=s2; V3_29=-h1;
V1_30=k2; V2_30=s1; V3_30=-h2;
V1_31=s2; V2_31=h1; V3_31=-k1;
V1_32=s1; V2_32=h2; V3_32=-k2;
V1_33=0; V2_33=h1; V3_33=-s;
V1_34=0; V2_34=-h1; V3_34=-s;
V1_35=s1; V2_35=-h2; V3_35=-k2;
V1_36=s2; V2_36=-h1; V3_36=-k1;
V1_37=h1; V2_37=-k1; V3_37=-s2;
V1_38=h2; V2_38=-k2; V3_38=-s1;
V1_39=h2; V2_39=k2; V3_39=-s1;
V1_40=h1; V2_40=k1; V3_40=-s2;
V1_41=-h1; V2_41=s; V3_41=0;
V1_42=h1; V2_42=s; V3_42=0;
V1_43=h2; V2_43=k2; V3_43=s1;
V1_44=h1; V2_44=k1; V3_44=s2;
V1_45=s1; V2_45=h2; V3_45=k2;
V1_46=s2; V2_46=h1; V3_46=k1;
V1_47=s1; V2_47=-h2; V3_47=k2;
V1_48=s2; V2_48=-h1; V3_48=k1;
V1_49=h1; V2_49=-k1; V3_49=s2;
V1_50=h2; V2_50=-k2; V3_50=s1;
V1_51=h1; V2_51=-s; V3_51=0;
V1_52=-h1; V2_52=-s; V3_52=0;
V1_53=-h2; V2_53=-k2; V3_53=-s1;
V1_54=-h1; V2_54=-k1; V3_54=-s2;
V1_55=-s1; V2_55=-h2; V3_55=-k2;
V1_56=-s2; V2_56=-h1; V3_56=-k1;
V1_57=-s1; V2_57=h2; V3_57=-k2;
V1_58=-s2; V2_58=h1; V3_58=-k1;
V1_59=-h1; V2_59=k1; V3_59=-s2;
V1_60=-h2; V2_60=k2; V3_60=-s1;

Vertix_Matrix =[...
    V1_1 V2_1 V3_1
    V1_2 V2_2 V3_2
    V1_3 V2_3 V3_3
    V1_4 V2_4 V3_4
    V1_5 V2_5 V3_5
    V1_6 V2_6 V3_6
    V1_7 V2_7 V3_7
    V1_8 V2_8 V3_8
    V1_9 V2_9 V3_9
    V1_10 V2_10 V3_10
    V1_11 V2_11 V3_11
    V1_12 V2_12 V3_12
    V1_13 V2_13 V3_13
    V1_14 V2_14 V3_14
    V1_15 V2_15 V3_15
    V1_16 V2_16 V3_16
    V1_17 V2_17 V3_17
    V1_18 V2_18 V3_18
    V1_19 V2_19 V3_19
    V1_20 V2_20 V3_20
    V1_21 V2_21 V3_21
    V1_22 V2_22 V3_22
    V1_23 V2_23 V3_23
    V1_24 V2_24 V3_24
    V1_25 V2_25 V3_25
    V1_26 V2_26 V3_26
    V1_27 V2_27 V3_27
    V1_28 V2_28 V3_28
    V1_29 V2_29 V3_29
    V1_30 V2_30 V3_30
    V1_31 V2_31 V3_31
    V1_32 V2_32 V3_32
    V1_33 V2_33 V3_33
    V1_34 V2_34 V3_34
    V1_35 V2_35 V3_35
    V1_36 V2_36 V3_36
    V1_37 V2_37 V3_37
    V1_38 V2_38 V3_38
    V1_39 V2_39 V3_39
    V1_40 V2_40 V3_40
    V1_41 V2_41 V3_41
    V1_42 V2_42 V3_42
    V1_43 V2_43 V3_43
    V1_44 V2_44 V3_44
    V1_45 V2_45 V3_45
    V1_46 V2_46 V3_46
    V1_47 V2_47 V3_47
    V1_48 V2_48 V3_48
    V1_49 V2_49 V3_49
    V1_50 V2_50 V3_50
    V1_51 V2_51 V3_51
    V1_52 V2_52 V3_52
    V1_53 V2_53 V3_53
    V1_54 V2_54 V3_54
    V1_55 V2_55 V3_55
    V1_56 V2_56 V3_56
    V1_57 V2_57 V3_57
    V1_58 V2_58 V3_58
    V1_59 V2_59 V3_59
    V1_60 V2_60 V3_60
    ];
figure, hold on
%--- for the 12 5-vertix faces of the polygon---%
Faces_Icosahedron5=[...
    12 13 47 49 20
    14 15 17 44 45
    48 46 27 22 23
    16 11 10 1 6
    19 52 53 8 9
    50 24 25 38 51
    18 5 4 60 41
    28 43 42 39 29
    21 30 31 36 26
    2 7 56 58 3
    40 59 57 33 32
    54 37 35 34 55
    ];
patch_info5.Vertices = Vertix_Matrix;
patch_info5.Faces=Faces_Icosahedron5;
patch_info5.FaceColor='r';
hold on, patch(patch_info5);
%--- for the 20 6-vertix faces of the polygon---%
Faces_Icosahedron6=[...
    11 12 13 14 15 16
    13 14 45 46 48 47
    47 48 23 24 50 49
    46 45 44 43 28 27
    15 16 6 5 18 17
    11 12 20 19 9 10
    44 17 18 41 42 43
    5 6 1 2 3 4 
    1 10 9 8 7 2 
    52 51 38 37 54 53
    23 22 21 26 25 24
    21 22 27 28 29 30
    42 41 60 59 40 39
    31 32 33 34 35 36
    33 34 55 56 58 57
    4 3 58 57 59 60
    20 49 50 51 52 19
    38 25 26 36 35 37
    29 39 40 32 31 30
    8 53 54 55 56 7
    ];
patch_info6.Vertices = Vertix_Matrix;
patch_info6.Faces=Faces_Icosahedron6;
patch_info6.FaceColor='g';
hold on, patch(patch_info6);
Keine
  • 45
  • 8
  • https://www.mathworks.com/matlabcentral/fileexchange/28106-texture-patch ? https://www.mathworks.com/matlabcentral/fileexchange/27764-map-texture-to-patch ? – Ander Biguri Aug 05 '15 at 14:02
  • 1
    Thanks, I already checked those functions. The first one only works if the polygons are triangles. Worst case scenarion I will "translate" the hexagons and pentagons of my icosahedron into triangles and use that, but I wanted to see if there was a more efficient way. Regarding the second one, it only works with huge amount of polygon faces. Instead of pasting the image on each face, it creates almost as many faces as pixels of the image and then uses the interpolation property of the patch to create something like the image. – Keine Aug 05 '15 at 14:04
  • "_it is not possible to use surf in this case, since the surfaces created using it always have a square as a base._" You have to explain this statement. I can't think about a surface/volume which can only be represented by a `patch` and not by a `surface`. And none of them require a "square" base ? Post the code you used to create your icosahedron. – Hoki Aug 05 '15 at 14:10
  • @Hoki maybe I am wrong but, surf(x,y,z) uses Z as a mxn matrix where the height values are stored, x as n positions, and y as m positions. So if I wanted to create a surface of a "floating" slanted hexagon, it would not be possible, since the matrix Z is a "square". – Keine Aug 05 '15 at 14:13
  • @Keine, you are right, `surf` require a `Z` matrix of size `mxn` but it does not have to be "square". You can still represent a polygon with just series of coordinates. As a hint consider the following: `x=[0 1 2 2 1 0];y =[1 0 1 2 3 2];z=[0 1 2 2 1 0];hp=patch(x,y,z,'r');` will create a 3D hexagon patch, but you won't be able to call `surf` with these coordinates. Now with **exactly** the same vertices, but reorganised : `x=[0 0;1 1;2 2];y =[1 2;0 3;1 2];z=[0 0;1 1;2 2];hs=surf(x,y,z);` will generate the very same 3D hexagon. But now it is a surface and you can apply texture map on it. – Hoki Aug 05 '15 at 16:13
  • @Hoki you are right, thanks. I managed to also create a pentagon using surf. However I do not intuitively get how it works. I created the pentagon by "repeating" one point; using the original points ``x=[-0.166 0 0.166 0.103 -0.1030], yy=[-0.206 -0.103 -0.206 -0.372 -0.372], zz=[0.436 0.5 0.436 0.333 0.333]`` and then creating the surf-able ``xx = [-0.166 -0.103;0 -0.103;0.166 0.103];yy=[-0.206 -0.372;-0.103 -0.372;-0.206 -0.372]; zz=[0.4363 0.333;0.5 0.333;0.436 0.333]; hs2=surf(x,y,z);`` Still, I feel I am missing something that makes this intuitive. – Keine Aug 06 '15 at 09:14

1 Answers1

1

This is a beginning of a solution but the usefulness will depend on what type of image you want to project on each surface.

The idea is to build your polygon as an assembly of surface rather than patch. Although it is not their strong suit, surface can be used to draw 3D flat polygon or even 'faceted' volumes like prism, dodecahedron, icosahedron, etc ...

Because the volume construction is a bit tedious, for the purpose of this example, I will only build a dodecahedron. It has less faces than your solid but I chose this one because it is composed only of pentagons, which is the tricky bit for Matlab surface. You'll see that the hexagons are much easier to handle if you apply this method to your problem.


Because the ordering of the coordinates is important to get a good surface, it would be too tedious to build the volume the way you did (calculating every vertices then finding the right ordering for each face). To make our life easier, we only build one surface, the base pentagon (you'll have to build 2 base surface, 1 pentagon and 1 hexagon).

The rest is just a matter of duplicating the base surface object (with copyobj), then place each copy in 3D where it belong (translate, rotate etc). We will also take advantage of the symmetry by building a half volume, then duplicating that and move it again.

Here we go:


I start by loading 6 images of wood texture in a cell array:

%% // Load textures
idxFaces = [1 2 3 4 5 6] ;
for iface = idxFaces
    imgface{iface} = imread( ['E:\ICONS\working_files\Misc\Woods\wood_texture_' num2str(iface) '.jpg'] ) ;
end

Then I define my base pentagon:

%% // Pentagon definition
% http://mathworld.wolfram.com/Pentagon.html
R = 1 ;          %// Radius of containing circle
Center=[0,0,0] ; %// center of the containing circle

c1 = R * (sqrt(5)-1)./4 ;
c2 = R * (sqrt(5)+1)./4 ;
s1 = R * (sqrt(10+2.*sqrt(5)))./4 ;
s2 = R * (sqrt(10-2.*sqrt(5)))./4 ;

xb = [-s1 -s2 ; 0 -s2 ; s1  s2] + Center(1) ;
yb = [ c1 -c2 ; R -c2 ; c1 -c2] + Center(2) ;
zb = zeros(size(xb))            + Center(3) ; 

hsb = surf( xb , yb , zb , 'CData',imgface{1},'FaceColor','texturemap','EdgeColor','none') ; %// first base pentagon surface

Then I define a few helper functions which will be reused to build the volume:

%% // define helper functions
%// Translate a graphic object by the vector v=[vx vy vz]
translate    = @(h,v) set( h, 'XData',get(h,'XData')+v(1) , 'YData',get(h,'YData')+v(2) , 'ZData',get(h,'ZData')+v(3) );
%// Retrieve the "direction" vector between two points of a graphic object
getDirection = @(h,id1,id2) [ h.XData(id1)-h.XData(id2) , h.YData(id1)-h.YData(id2) , h.ZData(id1)-h.ZData(id2)] ;
%// Retrieve the point coordinates of a graphic object
getPoint     = @(h,idp) [h.XData(idp) h.YData(idp) h.ZData(idp)] ;

Finally, I put them to good use, we replicate the base pentagon until we have the 6 faces of the lower volume:

%% // Lower volume
angleRot = 116 + 34/60 ;                %// pentagon dihedral angle  = 16°34'
dirPoints = [1 1;6 5;4 1;1 2;2 3;3 6] ; %// index of points which will be used to determinate direction and origin of the rotation

hs(1) = hsb ; %// include base surface into handle array
hax = gca ;   %// get current axis handle
for iface=2:6
    %// copy the base surface object
    hs(iface) = copyobj(hsb,hax) ;
    %// rotate it
    rotate(hs(iface), getDirection(hsb,dirPoints(iface,1), dirPoints(iface,2)) , angleRot , getPoint(hsb,dirPoints(iface,1)) )
    %// set the texture
    set( hs(iface) , 'CData',imgface{iface},'FaceColor','texturemap','EdgeColor','none') ;
end

Youhou, we have a half dodecahedron, now we simply replicate all that, flip, tranlate and rotate a last time to get the full volume:

%% Now copy all that, filp vertical then move up
ht = copyobj( hs,hax) ;                 %// copy the 6 surfaces in one go
rotate( ht , [0 1 0] , 180, [0 0 0])    %// flip them verticaly

%// translate then one by one
translationDistance = getPoint(hs(2),1) - getPoint(ht(2),2) ;
for iface = 1:6
    ht(iface).ZData = ht(iface).ZData + translationDistance(3) ;
end
rotate( ht , [0 0 1] , 36, [0 0 0])     %// Align the 2 sub-volumes

%% // final rendering
axis equal
axis off

And this is a quick rendering of the code above:

volume construction


Now as I hinted at the beginning, this will work ok if your images are "texture" like. If you want to project specific images onto these surfaces, the images will be deformed. Even triangle, pentagon or hexagon will render the images in a funny way.
Only square surfaces will be able to texture an image (which is always square) properly.

Check also the different answers in this topic: Animate text in MATLAB You'll find several examples of using texturemap on surfaces.

Community
  • 1
  • 1
Hoki
  • 11,637
  • 1
  • 24
  • 43