Twenty years from now you will be more disappointed by the things you didn’t do than by the ones you did do. So throw off the bowlines, sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover.

Mark Twain

Wavefront OBJ reader for building CGAL::Polyhedron_3

CGAL provides high quality generic half-edge data structure for representing polyhedral surfaces as well as many algorithms for mesh processing. However, CGAL doesn’t have any in-build support for building a polyhedron from Wavefront OBJ or PLY file. The following code is a basic OBJ file loader which reads vertex coordinates and faces (can be polygons) from OBJ file. Note that it doesn’t read vertex normals, face normals, or texture coordinates. Code is well commented and should be fairly obvious.

importOBJ() Function
#ifndef _SMESHLIB_IO_IMPORTOBJ_H_
#define _SMESHLIB_IO_IMPORTOBJ_H_

#include "CGAL/Polyhedron_incremental_builder_3.h"
#include "CGAL/Modifier_base.h"
#include "CGAL/exceptions.h"
#include <string>
#include <fstream>
#include <exception>

namespace SMeshLib {
namespace IO       {
;

// The BuildCgalPolyhedronFromObj class builds a CGAL::Polyhedron_3 from Wavefront OBJ file.
// This is very simple reader and only reads vertex coordinates and vertex index for faces.
// Faces can be polygons and doesn't have to be triangles.
template<class HDS>
class BuildCgalPolyhedronFromObj : public CGAL::Modifier_base<HDS>
{
public:
	
	BuildCgalPolyhedronFromObj(const std::string& fileName) : mFileName(fileName) {}
	
	void operator() (HDS& hds)
	{
		typedef typename HDS::Vertex   Vertex;
		typedef typename Vertex::Point Point;
		
		// Open obj file for reading.
		std::ifstream _file(mFileName.c_str());
		if(!_file)
		{
			return;
		}
		
		// Count the number of vertices and facets.
		// This is used to reserve memory in HDS.
		std::string _line;
		int _numVertices = 0;
		int _numFacets   = 0;
		while(_file.good())
		{
			std::getline(_file, _line);
			if(_line.size() > 1)
			{
				if(_line[0]=='v' && _line[1]==' ') {++_numVertices;}
				if(_line[0]=='f' && _line[1]==' ') {++_numFacets;}
			}
		}
		
		// Rewind file to beginning for reading data.
		if(!_file.good())
		{
			_file.clear();
		}
		_file.seekg(0);

		// Postcondition: hds is a valid polyhedral surface.
		CGAL::Polyhedron_incremental_builder_3<HDS> B(hds, true);
		
		// Load the data from OBJ file to HDS.
		B.begin_surface(_numVertices, _numFacets, int((_numVertices + _numFacets - 2)*2.1));
			
			std::string _token;
			while(!_file.eof())
			{
				_token = ""; // Reset token.
				_file >> _token;
				
				// if token is v then its a vertex.
				if(_token=="v")
				{
					double x, y, z;
					_file >> x >> y >> z;
					B.add_vertex(Point(x, y, z));
				}
				
				// There are 4 type of facets.
				// a     only vertex index.
				// a/b   vertex and texture index.
				// a/b/c vertex, texture and normal index.
				// a//c  vertex and normal index.
				else if(_token=="f")
				{
					// Read the remaining line for the facet.
					std::string _line;
					std::getline(_file, _line);
					
					// Split the line into facet's vertices.
					// The length of _vertices is equal to the number of vertices for this face.
					std::istringstream _stream(_line);
					std::vector<std::string> _vertices;
					std::copy(std::istream_iterator<std::string>(_stream), 
							  std::istream_iterator<std::string>(), 
							  std::back_inserter(_vertices));
					
					// For each vertex read only the first number, which is the vertex index.
					B.begin_facet();
					for(size_t i=0 ; i<_vertices.size() ; ++i)
					{
						std::string::size_type _pos = _vertices[i].find('/', 0);
						std::string _indexStr = _vertices[i].substr(0, _pos);
						B.add_vertex_to_facet(stoi(_indexStr)-1); // -1 is because OBJ file uses 1 based index.
					}
					B.end_facet();
				}
			}
			_file.close();
			
		B.end_surface();
	}
	
private:
	
	std::string mFileName;
};


// Import a OBJ file given by fileName to polyhedron.
// TPoly is a type of CGAL::Polyhdeon_3.
template<class TPoly>
void importOBJ(const std::string& fileName, TPoly* polyhedron)
{
	if(polyhedron)
	{
		try
		{
			// Build Polyhedron_3 from the OBJ file.
			BuildCgalPolyhedronFromObj<TPoly::HalfedgeDS> _buildPolyhedron(fileName);
			
			// Calls is_valid at the end. Throws an exception in debug mode if polyhedron is not
			// manifold.
			polyhedron->delegate(_buildPolyhedron);
			
			// CGAL::Assert_exception is thrown in the debug mode when 
			// CGAL::Polyhedron_incremental_builder_3 is destroyed in BuildCgalPolyhedronFromObj.
			// However, in the release mode assertions is disabled and hence no exception is thrown.
			// Thus for uniform error reporting, if the polyhedron is not valid then throw a dummy 
			// exception in release mode.
			if(!polyhedron->is_valid())
			{
				throw CGAL::Assertion_exception("", "", "", 0, "");
			}
		}
		catch(const CGAL::Assertion_exception&)
		{
			std::string _msg = "SMeshLib::importOBJ: Error loading " + fileName;
			throw std::exception(_msg.c_str());
		}
	}
}

};	// End namespace IO.
};	// End namespace SMeshLib.

#endif // _SMESHLIB_IO_IMPORTOBJ_H_
Using importOBJ()
#include "ImportOBJ.h"
#include "CGAL/Simple_cartesian.h"
#include "CGAL/Polyhedron_items_3.h"
#include "CGAL/HalfedgeDS_list.h"
#include "CGAL/Polyhedron_3.h"

typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Polyhedron_3<Kernel, 
	                       CGAL::Polyhedron_items_3, 
						   CGAL::HalfedgeDS_list> CgalPolyhedron;

void testImportOBJ()
{
	CgalPolyhedron _poly;
	SMeshLib::IO::importOBJ("Venus.obj", &_poly);
}
Downloads

ImportOBJ.h
TestImportOBJ.cpp


Zea Stem l.s. – Amscope 50PC Prepared Slides

Zea stem lateral section (l.s.) is the 50th slide in the Amscope 50PC prepared slides. Zea is a genus of true grasses in the family Poaceae of which corn is a member.

Micrographs [07 June 2014]
Amscope 50PC Prepared Slides

This post lists all the micrographs I have done from the Amscope 50PC prepared slides.


Zea Stem c.s. – Amscope 50PC Prepared Slides

Zea stem cross section is the 49th slide in the Amscope 50PC prepared slides. Zea is a genus of true grasses in the family Poaceae of which corn is a member.

Micrographs [07 June 2014]
Amscope 50PC Prepared Slides

This post lists all the micrographs I have done from the Amscope 50PC prepared slides.


Coprinus Mushroom Set – Amscope 50PC Prepared Slides

Cross-section of Coprinus mushroom set is the fourth slide in the Amscope 50PC prepared slides. The Coprinus is a small genus of mushrooms consisting of Coprinus comatus (the shaggy mane) and several of its close relatives [1].

Micrographs

The circular ring in the center is the stem of the mushroom. The center white circle suggests that the stem is hollow from inside. The lines from the stem to the edge forms the cap of the mushroom.

References
  1. http://en.wikipedia.org/wiki/Coprinus
Amscope 50PC Prepared Slides

This post lists all the micrographs I have done from the Amscope 50PC prepared slides.


Cotton Stem – Amscope 50PC Prepared Slides

Cross-section of cotton stem is the fifth slide in the Amscope 50PC prepared slides.

Micrographs [12 April 2014]
Micrographs [28 July 2014]
Amscope 50PC Prepared Slides

This post lists all the micrographs I have done from the Amscope 50PC prepared slides.


Aspergillus – Amscope 50PC Prepared Slides

Aspergillus whole mount (w.m.) is the second slide in the Amscope 50PC prepared slides set. Aspergillus is a genus consisting of several hundred mold species found in various climates worldwide [1]. A mold is a fungus that grows in the form of multicellular filaments called hyphae. In contrast, fungi that can adopt a single celled growth habit are called yeasts [2].

Micrographs
References
  1. http://en.wikipedia.org/wiki/Aspergillus
  2. http://en.wikipedia.org/wiki/Mold
Amscope 50PC Prepared Slides

This post lists all the micrographs I have done from the Amscope 50PC prepared slides.


Paramecium under Microscope in Pond Water

This is a video of a paramecium swimming around in water collected from pond in the Singapore Botanical Gardens.



Cabbage – Amscope 50PC Prepared Slides

The third slide in the Amscope 50PC prepared slides is the longitudinal section of cabbage. The individual cells of the cabbage are clearly visible in the slide.

Micrographs
Amscope 50PC Prepared Slides

This post lists all the micrographs I have done from the Amscope 50PC prepared slides.


Amscope 50 Piece Biology Prepared Microscope Glass Slides

I bought Amscope 50 piece biology prepared glass slides box along with Amscope B120B microscope to learn how to use a microscope properly and refine my techniques without worrying about making proper slides. This post list all the slides provided in the box. Each entry links to a post where I will discuss the specimen and show micrographs I recorded.

  1. Ascarid Egg (whole mount)
  2. Aspergillus (whole mount)
  3. Cabbage (longitudinal section)
  4. Coprinus Mushroom Set (cross section)
  5. Cotton Stem (cross section)
  6. Cucurbita Stem (longitudinal section)
  7. Dandelion Fuzz (whole mount)
  8. Dense Connective Tissue (section)
  9. Dog Cardiac Muscle (longitudinal section)
  10. Dog Esophagus (cross section)
  11. Dog Skeletal Muscle (longitudinal section & cross section)
  12. Dog Small Intestine (section)
  13. Dog Smooth Muscle (longitudinal section & cross section)
  14. Dog Squamous Epitheblium (whole mount)
  15. Dog Stomach (section)
  16. Earthworm (cross section)
  17. Honeybee Leg (whole mount)
  18. Honeybee Mouth Parts (whole mount)
  19. Honeybee Wings (whole mount)
  20. Housefly Mouth Parts (whole mount)
  21. Human Blood (smear)
  22. Hydra (longitudinal section)
  23. Hydrilla Verticillata Leaf (whole mount)
  24. Leaf of Winter Jasmine (cross section)
  25. Lillium Anther (cross section)
  26. Lillium Ovary (cross section)
  27. Locust Wing (whole mount)
  28. Loose Connective Tissue (section)
  29. Mantis Wing (whole mount)
  30. Nymphasa (cross section)
  31. Nymphasa of Apustio Stem (cross section)
  32. Onion Epidermis (whole mount)
  33. Penicillium (whole mount)
  34. Pig Motor Nerve (whole mount)
  35. Pine Leaf (cross section)
  36. Pine Pollen (whole mount)
  37. Pine Stem (cross section)
  38. Pumpkin Stem (cross section)
  39. Rabbit Artery and Vein (cross section)
  40. Rabbit Hyaline Cartilage (section)
  41. Rabbit Lymph Node (section)
  42. Rabbit Spinal Cord (cross section)
  43. Rabbit Testis (section)
  44. Stomata-Vicia Faba Leaf (whole mount)
  45. Sunflower Stcm (cross section)
  46. Tilia Stem (cross section)
  47. Wool Sheep (whole mount)
  48. Young Root of Broad Bean (cross section)
  49. Zea Stem (cross section)
  50. Zea Stem (longitudinal section)