C Libraries for Vector Maths?

I intend to create a C extension for lots of geometric manipulations. I definitely need functions for finding intersections between planes, edges, faces, etc.

I notice that in Ruby API, the Geom class has functions for intersections:
http://www.sketchup.com/intl/en/developer/docs/ourdoc/geom

…but in the C API equivalent, there is no such thing:
http://extensions.sketchup.com/developer_center/sketchup_c_api/sketchup/geometry_8h_source.html

Are there functions lurking in the API for this? Or maybe there is a library somewhere I can load and compute this myself? Maybe there are external libraries that people use?

Any help would be appreciated,
Thanks.

I use http://clb.demon.fi/MathGeoLib/nightly/
It’s not the fastest thing out there, but it’s pretty straightforward and easy to use.

2 Likes

I plan on looking at the OpenGL GLM library some day.
http://glm.g-truc.net/0.9.7/index.html

According to the website, it is header file based (I guess that means C++ templates everywhere). It seems to consist of numerous header files.

I thought at one time that a library like that could have its routines accelerated with the graphics card. If it is header files only, I don’t know if it would call the OpenGL routines that access a graphics card (OpenGL is an open specification, but the graphics driver source code is proprietary to the graphics card manufacturers).

I have used the Eigen library:
http://eigen.tuxfamily.org/index.php?title=Main_Page

It is more of a mathematician or engineer tool kit that supports matrices of any dimensions (which uses complex templates everywhere). It doesn’t cleanly match up with Sketchup’s GEOM module.

I wonder if the Sketchup develop team created their GEOM module from scratch, or if it was based off of an existing library?

It just means the library itself does not need compiled. No binary is generated to link against. You just need to include the headers in order to make the functions available in your compiled extension.

As far as libraries, libigl does matrices, but also a lot of other neat stuff and looks like it might be a good fit for SketchUp. Something like Dual quaternion skinning would be amazing for SketchUp, for example.

Thanks for all those suggestions. I had a look through each (though yet to be tested).

This looks right up my street. It seems to marry up to Sketchup’s geometry system well. Thank you for this! Performance-wise, I am sure it will beat using Ruby methods from C, so that’s a win.

I think this library is primarily intended for rendering applications. I can’t find much in the way of geometry manipulations here.

This seems quite promising, and I bet it is quick, being made for mathematicians / engineers. However, I didn’t immediately understand the documentation as well as MathsGeoLib.

It’s used in ‘dilay’ for geometry creation and manipulation… [ Jim posted a link Dilay for the other day ]
I started building a mac port, but had trouble linking GLM in…
I think I need to build it as a linked Library on a mac…

john

I’ve been looking into the MathsGeoLib some more. I like how it looks. I have one concern, however.

MathsGeoLib uses float numbers as the basis of the vectors. As far as I can understand, Sketchup uses double numbers, which as I understand has twice the precision. Have you had issues with prevision? As my manipulations need to make sure edges need to meet and edges of faces have to meet others, I am a little concerned by this. Have you experienced any issues in regards to precision before?

I don’t think I have had issues with precision. But I’m only generating transformations for placing components, not raw edges/faces.
Sketchup’s tolerance is 1/1000", is a C float more precise that 0.001? I think so.

You should try to have MathsGeoLib work on a complicated/tricky case and see if it’s precise enough.

A C float number gives around 7 “significant figures” of precision from what I have read. That means that I can achieve the 1/1000" (0.001") tolerance/accuracy for lengths of up to 9999" (9999.999"), or 254m (this is a simplification, I understand, as binary numbers don’t match perfectly to decimals). Any sizes larger than this, and I guess the numbers will start to truncate and become inaccurate.

I guess this is enough precision for most architectural scales. I would have liked an extra couple of digits to reassure me.

That said, I will give MathGeoLib a go. It definitely feels the most friendly to me.

Good to think out loud. Thanks.

I also wonder if it wouldn’t be possible to replace floats by doubles in the MGL code.
Might be worth looking into it.

I’ve had a look already. Floats are very much tangled into the code. There might be a way to do lots of regex find/replace though, if there are only a few source files that are required.

Ok, let me know if you find a solution (or switch to another library)

4 months into learning C++, I’ve ended up putting together my own library for Vector maths that plugs in nicely with SketchUp. I realised that it wasn’t that hard to do, and in fact much quicker than using an external library for what I wanted to do. I was surprised how few functions were required to cover most vector calculations (+, -, *, /, dot product, cross product, covered most). Going through the code of MathsGeoLib really helped me as a reference.

I’ve included the text for the header file for my library below in case anyone is interested. I’d be happy to share once it’s more polished and complete. The great advantage of my custom library is being able to quickly start calculating using SketchUp’s native structs that hold geometric data:
e.g Vector3D a = Point3D(SUPoint3D c) - Point3D(SUPoint3D b)); // This needs 3 lines of code with MathGeoLib

//
//  Geometry.h
//  SUEX_SkinUp
//
//  Created by Tom Kaneko on 31/08/2016.
//  Copyright © 2016 SketchUp. All rights reserved.
//

#ifndef Geometry_h
#define Geometry_h

#include <algorithm>
#include <vector>

#include <SketchUpAPI/geometry.h>
#include <SketchUpAPI/model/edge.h>
#include <SketchUpAPI/model/face.h>

/**
* Radians class deals with calculating radians.
*/
class Radians
{
private:
	const double PI = 3.141592653589793;

public:
  double m_val;

  Radians() {};
  Radians(const double &rhs) : m_val(rhs)
  { 
      if(rhs > (2*PI)) {
      	int numPi = rhs / (2*PI); // Get number of times 2pi fits in to rhs
				m_val = rhs - (numPi*2*PI);
      }
      else if(rhs < 0.0) {
      	int numPi = (rhs / (2*PI)) - 1; // Get number of times 2pi fits in to rhs
        m_val = rhs - (numPi*2*PI);
      }
  }
	
  // Copy constructor
  Radians(const Radians &radians):
  	m_val(radians.m_val) {
  }
  
  operator double() const { return m_val; }
  
  Radians &operator=(const Radians &radians) {
		if (this == &radians)
    	return *this;
    
    m_val = radians.m_val;
    return *this;
  }
  
  Radians operator+(const double value) {
  	return Radians(m_val + value);
  }
  Radians operator-(const double value) {
  	return Radians(m_val - value);
  }
  
 	bool closest(const Radians value) {
  	return Radians(m_val - value);
  }
  double operator*(const double multiplier) const {return m_val * multiplier;}

};

class Point3D;

/*
* Vector3D class is analagous to SUVector3D struct, and holds the same member variables.
* 
* Class methods are included to allow easy vector mathematics.
*/
class Vector3D {

	protected:
  SUVector3D m_vector;
  
  public:
  double &x;
  double &y;
  double &z;
  
  Vector3D();
  Vector3D( SUVector3D su_vector);
  Vector3D( double x, double y, double z);
  Vector3D( const SUEdgeRef &su_edge);

  /*
  * Convert to SUVector3D object
  */
  operator SUVector3D();
  
  /*
  * Convert to Point3D object
  */
  operator Point3D();
  
 	// Copy constructor
  Vector3D(const Vector3D &vector);
  
  // Copy assignment operator
  Vector3D &operator=(const Vector3D &vector);

  Vector3D operator+(const Vector3D &vector);
  Vector3D operator+(const SUVector3D &vector) {return *this + Vector3D(vector);}
  Vector3D operator-(const Vector3D &vector);
  Vector3D operator-(const SUVector3D &vector) {return *this - Vector3D(vector);}
  Vector3D operator*(const double &scalar) const {return Vector3D( x * scalar, y * scalar, z * scalar);}
  Vector3D operator/(const double &scalar) const {return Vector3D( x / scalar, y / scalar, z / scalar);}
	
  /**
  * Returns the vector of the Edge object
  */
  static SUVector3D vector_from_edge(const SUEdgeRef &su_edge);
  
  /*
  * Returns the length of the vector
  */
  double length() const;

  /*
  * Returns the angle between this vector and that of another.
  */
  double angle(const Vector3D vector_b) const;
  
  /**
  * Returns dot product with another vector
  */
  double dot(const Vector3D vector2) const;
  
  /**
  * Returns cross product with another vector
  */
  Vector3D cross(const Vector3D vector2) const;


};

static Vector3D operator*(const double &lhs, const Vector3D &rhs)
{  return rhs * lhs;}


/*
* Point3D class is analagous to SUPoint3D struct, and holds the same variables.
* 
* Class methods are given to allow easy vector mathematics.
*
* Point3D inherits from Vector3D, as the concept of a point and a vector is interchangeable in vector mathematics.
*/
class Point3D : public Vector3D {
	public:
  Point3D( SUPoint3D su_point);
  Point3D( SUVector3D su_vector);
  
  // Copy assignment operator
  Point3D &operator=(const Point3D &vector);
  
  operator SUPoint3D() { return SUPoint3D {m_vector.x, m_vector.y, m_vector.z}; }

};

/*
* Plane3D class is analagous to SUPlane3D struct, and holds the same variables.
* 
* Class methods are included to allow easy vector mathematics.
*/
class Plane3D {
	protected:
  SUPlane3D m_plane;
  
  public:
  double &a;
  double &b;
  double &c;
  double &d;
  
  Plane3D(const SUPlane3D plane);
  Plane3D(double a, double b, double c, double d);
  Plane3D(const SUFaceRef &face);

 // Copy constructor
  Plane3D(const Plane3D &plane);
  
  // Overload copy assignment operator
  Plane3D &operator=(const Plane3D &plane);
  
  /**
  * Returns the normal of the plane
  */
  Vector3D normal() const;
  
  /**
  * Returns unit vector along line of intersection between two planes
  */
  Vector3D intersection(const Plane3D plane2) const;
  
	double angle_with(const Plane3D plane2) const;

  /**
  * Checks if the plane is parallel with another.
  */
	bool parallel(const Plane3D plane2) const;

  /**
  * Returns SUPlane3D of SUFaceRef object
  */
  static SUPlane3D get_plane(const SUFaceRef &face);
  
  /**
  * Implicit conversion to SUPlane3D
  */
  operator SUPlane3D();
  
};



#endif /* Geometry_h */