element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Benefits of Membership
    • Achievement Levels
    • Members Area
    • Personal Blogs
    • Feedback and Support
    • What's New on element14
  • Learn
    Learn
    • Learning Center
    • eBooks
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Dev Tools
    • Manufacturers
    • Raspberry Pi
    • RoadTests & Reviews
    • Avnet Boards Community
    • Product Groups
  • Store
    Store
    • Visit Your Store
    • Choose Another Store
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
Raspberry Pi
  • Products
  • More
Raspberry Pi
Blog A second Pi Project: 3D Xmas Trees!
  • Blog
  • Forum
  • Documents
  • Events
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Raspberry Pi requires membership for participation - click to join
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: shabaz
  • Date Created: 30 Jul 2017 12:06 AM Date Created
  • Views 273 views
  • Likes 5 likes
  • Comments 2 comments
Related
Recommended
  • coding
  • rpibeginner
  • code_library
  • rpi
  • raspberry_pi_getting_started

A second Pi Project: 3D Xmas Trees!

shabaz
shabaz
30 Jul 2017

Introduction

In a previous blog, there was a project for complete beginners, to draw a tree with zero programming experience required.

In this blog post, we go 3D. Again, no programming experience is needed to follow this project and extend it to draw different 3D objects. We will also rotate objects.

image

 

Designing the Tree

First off, a tree was sketched on graph paper. It was decided that the origin (0,0) point would be at the bottom of the tree, so that the base of the tree trunk has co-ordinates (-10,0) and (10,0) as shown in the sketch. All the other points were also marked onto the graph paper.

image

 

 

 

To get this representation into the computer, one could use lots of line statements as in the previous blog post, such as the following to draw the base of the trunk:

g2_line(id, -10, 0, 10, 0);

 

Such a technique would result in a lot of code! Ordinarily the desire is to write as little as possible. There is a theory that for every ten lines of code that is written, there will likely be one software bug. It is better to write a 10-line program and fix the (likely) single bug, than write 100 lines and search for 10 bugs.

 

Nevertheless, there are 15 co-ordinates in the sketch, and that will likely translate to at least 15 lines of code to represent the co-ordinates. Perhaps it could be halved by recognizing that there is symmetry in the tree, but for now code won’t be so optimized.

 

The 15 points can be just typed out. Since the tree is to be in three dimensions, we will actually use (x,y,z) co-ordinates, not (x,y):

 

double points[15][3]={
  {-10, 0, 0},
  {-10, 40, 0},
  {-70, 30, 0},
  {-20, 80, 0},
  {-60, 70, 0},
  {-10, 120, 0},
  {-40, 110, 0},
  {0, 160, 0},
  {40, 110, 0},
  {10, 120, 0},
  {60, 70, 0},
  {20, 80, 0},
  {70, 30, 0},
  {10, 40, 0},
  {10, 0, 0}};

 

This is really a flat 2D Xmas tree in three dimensions, but there is nothing stopping anyone from designing a more fancy truly 3-dimensional tree.

Although the numbers are in blocks of three, in reality the computer stores all these numbers in one long block of memory. The memory will contain -10, 0, 0, -10, 40, 0, -70, 30, 0….

 

Notice the curly brackets (also known as curly braces). Generally you can provide the computer with a sequence or array of numbers by placing them inside curly braces and separating each number with a comma.

 

The example above is more complex because there are curly braces within the outer curly braces. There is a sequence of fifteen sequences of three numbers representing x, y and z values.

 

Rotation

Sines and cosines can be used to rotate points by any desired angle. It is beyond the scope of this blog post, but code was written to perform the rotation. It isn’t important to know how it works, just that it can take a three-dimensional point and an angle, and spit out a modified 3-dimensional result. A vector can be rotated using sine and cosines, and the precise formula isn’t essential to know (it is part of math lessons for schoolkids around the age of 16-18, but even if you have not studied this, you could use google to find the right formula).

 

So, a rotation of 90 degrees about the y-axis could be imagined to be a paper cut-out tree that was held vertically and turned by 90 degrees. A rotation of 90 degrees about the x-axis would result in the paper being placed horizontally on a table. 90 degrees about the z-axis would result in the tree sideways on edge on the table.

 

Here is the code to perform rotation about the y-axis:

 

  r[0]=cos(a)*p[0]-sin(a)*p[2];
  r[1]=p[1];
  r[2]=sin(a)*p[0]+cos(a)*p[2];

 

In this code, r[0] represents the x co-ordinate of the result, and r[1] represents the y co-ordinate of the result. The letter 'a' is a variable that contains the desired rotation angle.

The input x, y, and z co-ordinates are p[0], p[1] and p[2] respectively. The numbers in the square brackets are an index, the computer stores all these values in memory in sequence. It was just convenient in the follow-on code for these values to be in a sequential array for easier storage in memory, because we want to save many co-ordinates in memory, for the entire Xmas tree. Whenever more than one item needs to be stored, it is worth exploring if an array of values can be used instead; it can save coding effort.

 

Isometric View

The screen only displays two dimensions so some form of translation is needed from the 3D world to 2D. In this example, we do an isometric transformation and again the exact formula for this isn’t important. The important thing is that the result is an array of two-dimensional points. The formula takes the x,y,x co-ordinates and converts then to x,y co-ordinates.

 

Finally, all the mapped points are drawn connected by lines.

 

Putting it all together

The entire code is shown here. Like the earlier blog post, it isn’t necessary to have a detailed understanding to begin to see what this code does. Examining the code, it can be seen that the first few lines are a description. As before, the next lines are referring to g2 which is the graphics library.

 

Further down there are some lines with the text ‘xrot’, ‘yrot’ and ‘zrot’ and this is the code that takes a 3D point and rotates it by an angle.

 

There is also some code called ‘to2d’ that converts a 3D point into a location on a two-dimensional isometric projection.

 

After that there is code titled ‘main function’. The array of the fifteen 3D points of the Xmas tree are there, and it is followed by some code that prints a message on the screen and prompts the user to type in an angle. All fifteen points are then rotated by that angle, and then converted to isometric projections. Finally, the lines are drawn between each point and the next consecutive point, to ‘join the dots’.

 

 

/****************************
 * 3D Xmas Tree
 * 
 * rev 1 June 2017
 ****************************/


// include
#include <stdio.h>
#include <math.h>
#include <g2.h>
#include <g2_X11.h>


// defines
#define width 400
#define height 300
#define NUMPOINTS 15
#define WHITE 0
#define BLACK 1
#define BLUE 3
#define GREEN 7
#define RED 19
#define YELLOW 25


/****************************
 * functions
 ****************************/


// rotation functions
// these rotate a 3D point p by angle a,
// and store the result in r
void
xrot(double* p, double a, double* r)
{
  r[0]=p[0];
  r[1]=cos(a)*p[1]+sin(a)*p[2];
  r[2]=cos(a)*p[2]-sin(a)*p[1];
}


void
yrot(double* p, double a, double* r)
{
  r[0]=cos(a)*p[0]-sin(a)*p[2];
  r[1]=p[1];
  r[2]=sin(a)*p[0]+cos(a)*p[2];
}


void
zrot(double* p, double a, double* r)
{
  r[0]=cos(a)*p[0]+sin(a)*p[1];
  r[1]=cos(a)*p[1]-sin(a)*p[0];
  r[2]=p[2];
}


// 3D to 2D mapping function
// This maps a 3D point p to a 2D point r
// in an isometric style representation
void
to2d(double* p, double* r)
{
  r[0]=(p[0]-p[2])*sqrt(3)/2;
  r[1]=((p[0]+p[2])*0.5)+p[1];
}


/****************************
 * main function
 ****************************/
int
main(void)
{
  int id;
  int i;
  double angle;
  int forever=1;


// These points represent an Xmas tree
  double points[NUMPOINTS][3]={
  {-10, 0, 0},
  {-10, 40, 0},
  {-70, 30, 0},
  {-20, 80, 0},
  {-60, 70, 0},
  {-10, 120, 0},
  {-40, 110, 0},
  {0, 160, 0},
  {40, 110, 0},
  {10, 120, 0},
  {60, 70, 0},
  {20, 80, 0},
  {70, 30, 0},
  {10, 40, 0},
  {10, 0, 0}};


  double points_manip[NUMPOINTS][3];
  double points2d[NUMPOINTS][2];


  id=g2_open_X11(width, height);
  
while(forever)
{
printf("Enter an angle in degrees (0-360): ");
scanf("%lf", &angle);
printf("angle is %f\n", angle);
angle=angle*3.14/180;

g2_clear(id);
g2_pen(id, BLACK);


  for (i=0; i<NUMPOINTS; i++)
  {
  // rotate
    yrot(points[i], angle, points_manip[i]);
    // get the 2D point
      to2d(points_manip[i], points2d[i]);


// move (translate) the 2D point so that it sits on the screen
      points2d[i][0]+=100;
      points2d[i][1]+=100;


  }


// draw the 2D lines
  for (i=0; i<NUMPOINTS-1; i++)
  { 
    g2_line(id, points2d[i][0], points2d[i][1], points2d[i+1][0], points2d[i+1][1]);
  }
  g2_line(id, points2d[NUMPOINTS-1][0], points2d[NUMPOINTS-1][1], points2d[0][0], points2d[0][1]);


} // end of while(forever)


// these lines won't ever execute
  getchar();
  g2_close(id);
  return(0);
}

 

To run the code, follow the steps in the earlier blog post to install the graphics library, and then save the code here in a file called (say) 3dtree.c and then type the following to compile the code:

gcc 3dtree.c -lg2 -lm -o 3dtree

 

To run it, type:

./3dtree

 

The program will prompt you to type an angle and then press Enter. It will draw the tree rotated at that angle.

 

Next Steps

As an experiment, try to imagine a cube in 3D space, write down its x,y,z co-ordinates for all eight corners of the cube, and then rotate and convert to isometric. It would be great to see people’s attempts.

 

In summary the code in this blog demonstrated a few techniques; by experimenting with the code and trying to create new shapes to rotate, the power of arrays and 'for' loops is exercised. The ability to take user input and printing messages is very useful when debugging. Not all the code will be understandable by a complete beginner, but enough is understandable to be able to copy the code and modify it to draw and manipulate complex shapes under user control. The rest of the code (including all the brackets and semi-colons and so on) will begin to make sense as more software based projects are attempted; there is no need to try to understand it all at once.

 

Here is my attempt at drawing the death star using same code, very slightly modified. The circles are actually made of lines; the array of points consisted of 40 points per circle and therefore when the points were joined by straight lines, it approximated a circle.

image

 

The code of course still allows the object to be rotated by selecting a desired angle. It would be interesting to rotate a physical object at the same time. Servos are useful for that! Another idea would be to read input from an external sensor such as an accelerometer, and move the 3D representation accordingly.

 

One could also take the ideas here and (say) draw a robot arm in 3D and move a real 3D arm at the same time.

  • Sign in to reply

Top Comments

  • DAB
    DAB over 5 years ago +1
    Nice project. I may copy some of your design to do an indoor lightning display using LED's and cotton batting. DAB
  • Problemchild
    Problemchild over 5 years ago +1
    Nice way to teach someone about arrays with out the stress . I'll keep the Christmas tree rotating untill a bit later in the year however!! :-)
  • Problemchild
    Problemchild over 5 years ago

    Nice way to teach someone  about arrays with out the stress .

    I'll keep the Christmas tree rotating untill a bit later in the year however!!

     

    :-)

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • DAB
    DAB over 5 years ago

    Nice project.

     

    I may copy some of your design to do an indoor lightning display using LED's and cotton batting.

     

    DAB

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2023 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • Facebook
  • Twitter
  • linkedin
  • YouTube