Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Edit: All the four answers to this question are great, and if you're interested, you should take a look at all the answers. Nevertheless, belisarius' code was accepted since it was closest to what I had in mind.

I'm trying to use Mathematica to help students better understand 3-dimensional views of objects, specifically the "plan view", the "side elevation view" and the "front elevation view", as elaborated upon here.

Given the following example "building", I was able to combine Graphics3D primitives to simulate the object using the following code.

enter image description here

dee = Graphics3D[{Green, Opacity[0.6], Cuboid[{0, 0, 0}, {2/3, 1, 1}],
    Red, Polygon[{{{2/3, 1/2, 0}, {2/3, 1/2, 1}, {3/2, 1/2, 0}}, 
       {{2/3, 1, 0}, {2/3, 1, 1}, {3/2, 1, 0}}, 
       {{2/3, 1/2, 0}, {2/3, 1, 0}, {3/2, 1, 0}, {3/2, 1/2, 0}}, 
       {{2/3, 1/2, 1}, {2/3, 1, 1}, {3/2, 1, 0}, {3/2, 1/2, 0}}}]}]

However, as you can see, the code is rather convoluted, with a great deal of time spent making the red prism. In this case, it was still feasible to manually generate the prism, but what I'm interested in is,

Is there a way to generate a 3D object which is made up of a combination of prisms simply by identifying the vertices at the corner of the object?


If you're interested, my code to allow students to see the three views is as follows, with an example result below.

planviewer = 
  TableForm@{{"3d", "Side", "Front", "Top"}, 
    {Show[#, ViewPoint -> {1, -1, 1}], 
     Show[#, ViewPoint -> {∞, 0, 0}], 
     Show[#, ViewPoint -> {0, -∞, 0}], 
     Show[#, ViewPoint -> {0, 0, ∞}]}, 
    {"", 
     Show[#, ViewPoint -> Right], 
     Show[#, ViewPoint -> Front], 
     Show[#, ViewPoint -> Above]}} &;

enter image description here

The following code allows them to manipulate the viewpoint dynamically.

Manipulate[
 Show[dee, ViewPoint -> {10^a, -(10^b), 10^c}], {a, 0, 3}, {b, 0, 3}, {c, 0, 3}]
share|improve this question
1  
If you want to teach about the different View* functions and what they do, you might find this answer useful. –  rm -rf Mar 30 '13 at 16:59
add comment

4 Answers 4

up vote 17 down vote accepted

There are some tricks ... Specifying the prism's vertices is enough (you don't need to take care of the faces) if you use some undocumented methods for finding the convex hull:

v = {{2/3, 1/2, 0}, {2/3, 1/2, 1}, {2/3, 1, 0}, {2/3, 1, 1}, {3/2, 1/2, 0}, {3/2, 1, 0}};
prism@v_:=Cases[ComputationalGeometry`Methods`ConvexHull3D[v,Graphics`Mesh`FlatFaces->False],
                                                                 _GraphicsComplex, Infinity];

Graphics3D[{Green, Opacity[0.6], Cuboid[{0, 0, 0}, {2/3, 1, 1}], Opacity[.6], Red, prism@v}]

Mathematica graphics

share|improve this answer
    
This is easily turned into a function, polyhedron[v_] := Cases[.. Very nice. (+1) –  Michael E2 Mar 30 '13 at 18:21
    
@MichaelE2 Thanks! Rewritten as a function now. –  belisarius Mar 30 '13 at 18:43
    
@belisarius how do you find out about all these undocumented questions? I was trying to search for it, and saw some similar questions on this site, but I think that's the first time I've seen it. Edit: ninja'd by bill. –  Vincent Tjeng Mar 31 '13 at 3:30
    
It's not on this list, by the way :) : mathematica.stackexchange.com/questions/809/… –  Vincent Tjeng Mar 31 '13 at 3:38
    
@VincentTjeng I don't remember how I found this one, probably following some InternalTrace. You can find similar things trying Names["ComputationalGeometry`Methods`*"] –  belisarius Mar 31 '13 at 5:55
show 3 more comments

GraphicsComplex is probably what you are looking for. For example, define the vertices for the 3D polygon:

v = {{2/3, 1/2, 0},{2/3, 1/2, 1},{3/2, 1/2, 0},{2/3, 1, 0},{2/3, 1, 1},{3/2, 1, 0}};

and make a list of which vertices should connect to each other:

i = {{1, 2, 3}, {4, 5, 6}, {1, 2, 5, 4}, {1, 3, 6, 4}, {2, 3, 6, 5}};

The first two elements of i represent the two triangular faces of the prism; the final three elements are the three rectangular faces. This is plotted using

Graphics3D[{Opacity[.8], Red, GraphicsComplex[v, Polygon[i]]}]

or you can plot the green cube plus the red prism together:

Graphics3D[{Green, Opacity[0.6], Cuboid[{0, 0, 0}, {2/3, 1, 1}], 
  Opacity[.6], Red, GraphicsComplex[v, Polygon[i]]}]

which gives the figure below. The code is modified from the documentation in GraphicsComplex where you can find all sorts of neat 3D tricks. If they have access, I think the students would benefit from being able to manipulate the 3D illustration themselves -- this seems like a good application for deployed .cdf's.

cube and prism

share|improve this answer
    
Thanks for the answer! Would it be possible for the one to write some code that immediately identifies which of vertices should be connected to each other to form the faces, keeping in mind that the faces of the prism may not always be in the same plane? Also, I notice that the part of the red prism joining the green cuboid is actually a triangle, and not a rectangle ... is that a problem or simply a visual illusion? –  Vincent Tjeng Mar 30 '13 at 10:21
    
The little triangle on the adjoining face is an illusion that has to do with the shading -- when you rotate the graphic it changes. But to your first question, the answer is no. After all, how can it know what edges you want to connect if you don't tell it? You will get something no matter what edges you connect -- only one of these is the figure you presumably want. –  bill s Mar 30 '13 at 10:33
    
@VincentTjeng: yes, you can connect the vertices automagically because the faces must form the convex hull. See my answer –  belisarius Mar 30 '13 at 18:54
    
Very nice... how does one find "undocumented features"? –  bill s Mar 31 '13 at 3:17
    
bill I don't remember how I found this one, probably following some InternalTrace. You can find similar things trying Names["ComputationalGeometry`Methods`*"] –  belisarius Mar 31 '13 at 5:59
add comment

Take a look at the output of PolyhedronData[{"Prism", 3}, "Faces"]}, which may help.

Note this isn't exactly a direct answer, but I think the optimal solution here is a tool that would let you... well, like this:

whatThe[n_] := Module[{list = {}, grid = False},
   Grid@List@{
      EventHandler[#, {"KeyDown", "k"} :> (grid = Not[grid])] &[

       Graphics3D[{
            EventHandler[MouseAppearance[Sphere[#, .06],
              Style["\[RightUpDownVector]\[LeftUpDownVector]", Darker@Blue, Large]],
            {"MouseClicked" :> AppendTo[list, ##]}] & /@ Tuples[Range[n], 3],

         (*Opacity[.3],*)Dynamic[Polygon[list]], Thick, Dynamic[Line[list]],
         Thin, Lighter[Gray, .8], Dynamic[If[grid, Line[                
            Select[Subsets[Tuples[Range[n], 3], {2}],
             EuclideanDistance @@ ## == 1 &]], {}]]},

        Boxed -> True, ImageSize -> Large, Axes -> True]],

      Graphics3D[Dynamic[Polygon[list]]], 
      EventHandler[Dynamic[Column[list]],
       {"MouseClicked" :> (CopyToClipboard[list]; Beep[])}]}
   ];

whatThe[4]

You click on points to add them to a list. MAGIC!!! It takes some getting used to... here's one of my attempts at creating a prism:

enter image description here

I couldn't tell what order you have to construct the list in for the resulting polygon to be reasonable, but at the very least it might help you pick some points out. It's also another example of just how ridiculously powerful Mathematica is. The basic working version of this took me like 4 minutes to make. O.O

(Note: A simple improvement might be to use a hotkey to cut the list up as you build the polygon).

Update. Using belisarius's convex hull code:

whatThe[n_] := Module[{list = {}, faces, grid = False},
   faces[v_] := Cases[ComputationalGeometry`Methods`ConvexHull3D[v, 
      Graphics`Mesh`FlatFaces -> False], _GraphicsComplex, Infinity];

   Grid@List@{
      EventHandler[#, {"KeyDown", "k"} :> (grid = Not[grid])] &[

       Graphics3D[{EventHandler[
            MouseAppearance[Sphere[#, .06], 
             Style["\[RightUpDownVector]\[LeftUpDownVector]", 
              Darker@Blue, Large]],
            {"MouseClicked" :> AppendTo[list, ##]}] & /@ Tuples[Range[n], 3],

         (*Opacity[.3],*)Dynamic[faces[list]],
         Thin, Lighter[Gray, .8], Dynamic[If[grid, Line[
            Select[Subsets[Tuples[Range[n], 3], {2}], 
             EuclideanDistance @@ ## == 1 &]], {}]]},

        Boxed -> True, ImageSize -> Large, Axes -> True]],

      Graphics3D[Dynamic[faces[list]]],
      EventHandler[Dynamic[Column[list]],
       {"MouseClicked" :> (CopyToClipboard[list]; Beep[])}]}];

enter image description here

share|improve this answer
    
+1 amazing. and it helps with the first part of translating the problems in the students' worksheets to the prism I want. now I just need to modify the code such that it accepts multiple convex hulls representing the multiple prisms :) –  Vincent Tjeng Mar 31 '13 at 2:58
add comment

You can get away with specifying even less than all the points.

A (right) prism is a planar figure extruded in an orthogonal direction. It would suffice, then, to give the coordinates of that figure (thereby describing one of the two "ends" of the prism) and its intended height. The figure in the question can therefore be created as a collection of two prisms (no Cuboid if you don't care to use it) like this:

Graphics3D[{Opacity[0.6], 
  Green, prism[{{0, 0, 0}, {2/3, 0, 0}, {2/3, 1, 0}, {0, 1, 0}}, 1],
  Red, prism[{{2/3, 1, 0}, {3/2, 1, 0}, {2/3, 1, 1}}, 1/2]}]

Reproduction

The calculations come down to

  1. Find a basis for the polygon's plane by orthogonalizing its vertices relative to their barycenter;

  2. Perform the extrusion by taking the cross product of the basis elements (normalized to the desired height) and adding that to each of the polygon's vertices; and

  3. Describe how the vertices are connected to form the two polygonal ends and each of the sides.

Here is such a solution. Its arguments are pt, a list of the (3D) vertices around the (nondegenerate) polygon, and height, the height of the prism. It produces a 3D graphics object.

prism[pt_List, height_] := Block[{n = Length[pt], normal},
  normal = Cross @@ Orthogonalize[# - Mean[pt] & /@ pt][[1 ;; 2]];
  GraphicsComplex[pt~Join~(height normal + # & /@ pt), 
   {Polygon[Range[n]], Polygon[Range[2 n, n + 1, -1]], 
    Polygon[{#, n + #, n +  Mod[# + 1, n, 1], Mod[# + 1, n, 1]}] & /@ Range[n]}]]

To see it in action, let's generate a polygon with a random position and orientation:

basis = RandomReal[NormalDistribution[0, 1], {2, 3}];
pt = ({Cos[#], Sin[#]} & /@ Range[0, 2 \[Pi], 2 \[Pi]/7]).basis

Here is the original polygon as a solid black "floor" drawn with two prisms, one with a positive height and another with a negative height:

Graphics3D[{Opacity[0.75], prism[pt, 1], prism[pt, -1/2], Opacity[1], Black,  Polygon[pt]}]

Prism

This approach is easily extended to non-right prisms by replacing height by the extrusion vector (describing one of the "vertical" edges of the prism) and using that instead of height normal in the code.

share|improve this answer
    
nice application of math :) just a quick question, when you code as prism[pt_List, height_], pt_List is written as such since it is a list, right? so if i were to code a function f[a_String, b_String], then the variables would be a, b and they must be strings? –  Vincent Tjeng Mar 31 '13 at 3:35
    
See the documentation on Blank. –  whuber Mar 31 '13 at 13:19
    
Got it, thank you! –  Vincent Tjeng Apr 1 '13 at 3:01
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.