stl_stats

This is a  small C++ program to iterate over a STL file and to print out a few things:

  1. Max/Min for X, Y and Z –> Bounding Box
  2. Number of layers
  3. “Useful” layers : given a minimum height, if some layers on Z axis are too small it performs a merge. Loosely speaking, if the ratio between “useful” layers and  real layers of the model is too low, it means that the printing of this given model can potentially be not nice in between some layers (it is a sampling issue).
    • Example of problematic details on the bottom of Darth Vader Pen Cup:

NB: For reading the STL file, it is a simple copy-paste from the really good OpenSCAD.

Usage:

stl_stats filename.stl [minLayerHeight]

Dependencies:

boost_regex and boost_system

Output examples:

 

./stl_stats  ../../../Téléchargements/20mm-box.stl
BinarySTL = 0
Layer 0: Axis Z 0
Layer 1: Axis Z 10
—> New Layer height = 10
Number of layers 2
Useful layers 1 (small bug actually it is 2)
Face Number = 12
XMin = -10 XMax = 10, Distance = 20
YMin = -10 YMax = 10, Distance = 20
ZMin = 0 ZMax = 10, Distance = 10
Minimum layer height = 0.3
Max number of layers = 33.3333

./stl_stats  ../../../Téléchargements/darth_vader_pen_cup.stl

Layer 1142: Axis Z 80.001
Previous layer too thin, useless
Number of layers 1143
Useful layers 115
Face Number = 5406
XMin = -36.001 XMax = 54, Distance = 90.001
YMin = -49 YMax = 41.001, Distance = 90.001
ZMin = -0.001 ZMax = 80.001, Distance = 80.002
Minimum layer height = 0.3
Max number of layers = 266.673

./stl_stats  ../../../Téléchargements/darth_vader_pen_cup.stl 0.1

Layer 1142: Axis Z 80.001
Previous layer too thin, useless
Number of layers 1143
Useful layers 214
Face Number = 5406
XMin = -36.001 XMax = 54, Distance = 90.001
YMin = -49 YMax = 41.001, Distance = 90.001
ZMin = -0.001 ZMax = 80.001, Distance = 80.002
Minimum layer height = 0.1
Max number of layers = 800.02

 

Source code:

#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>

#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope

#include <boost/detail/endian.hpp>
#include <boost/cstdint.hpp>

#include <map>

//CODE COMING FROM OPENSCAD

#define STL_FACET_NUMBYTES 4*3*4+2
// as there is no 'float32_t' standard, we assume the systems 'float'
// is a 'binary32' aka 'single' standard IEEE 32-bit floating point type
union stl_facet {
	uint8_t data8[ STL_FACET_NUMBYTES ];
	uint32_t data32[4*3];
	struct facet_data {
	  float i, j, k;
	  float x1, y1, z1;
	  float x2, y2, z2;
	  float x3, y3, z3;
	  uint16_t attribute_byte_count;
	} data;
};

inline void uint32_byte_swap( uint32_t &x )
{
#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3
	x = __builtin_bswap32( x );
#elif defined(__clang__)
	x = __builtin_bswap32( x );
#elif defined(_MSC_VER)
	x = _byteswap_ulong( x );
#else
	uint32_t b1 = ( 0x000000FF & x ) << 24;
	uint32_t b2 = ( 0x0000FF00 & x ) << 8;
	uint32_t b3 = ( 0x00FF0000 & x ) >> 8;
	uint32_t b4 = ( 0xFF000000 & x ) >> 24;
	x = b1 | b2 | b3 | b4;
#endif
}

inline void read_stl_facet( std::ifstream &f, stl_facet &facet )
{
	f.read( (char*)facet.data8, STL_FACET_NUMBYTES );
#ifdef BOOST_BIG_ENDIAN
	for ( int i = 0; i < 12; i++ ) {
		uint32_byte_swap( facet.data32[ i ] );
	}
	// we ignore attribute byte count
#endif
}

inline int readStlFile(const char *filename, double minLayerHeight = 0.3 ) {
  // Open file and position at the end
  std::ifstream f(filename, std::ios::in | std::ios::binary | std::ios::ate);
  if (!f.good()) {
    std::cerr << "WARNING: Can't open stl file:" <<  filename << std::endl;
    return -1;
  }

  boost::regex ex_sfe("solid|facet|endloop");
  boost::regex ex_outer("outer loop");
  boost::regex ex_vertex("vertex");
  boost::regex ex_vertices("\\s*vertex\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)");

  bool binary = false;
  std::streampos file_size = f.tellg();
  f.seekg(80);
  uint32_t facenum = 0;
  if (f.good() && !f.eof()) {
    f.read((char *)&facenum, sizeof(uint32_t));
#ifdef BOOST_BIG_ENDIAN
    uint32_byte_swap( facenum );
#endif
    if (file_size ==  static_cast<std::streamoff>(80 + 4 + 50*facenum)) {
      binary = true;
    }
  }
  f.seekg(0);

  //START OF MY STAT STUFF
  std::cout << "BinarySTL = " << binary << std::endl;

  double XMin = 1000000000.0, XMax = -10000000000.0;
  double YMin = 1000000000.0, YMax = -10000000000.0;
  double ZMin = 1000000000.0, ZMax = -10000000000.0;

  facenum = 0;

  std::map<double, uint32_t> stlLayers; //number of layers

  //END OF MY STAT STUFF

  char data[5];
  f.read(data, 5);
  if (!binary && !f.eof() && f.good() && !memcmp(data, "solid", 5)) {
    int i = 0;
    double vdata[3][3];
    std::string line;
    std::getline(f, line);
    while (!f.eof()) {
      std::getline(f, line);
      boost::trim(line);
      if (boost::regex_search(line, ex_sfe)) {
	continue;
      }
      if (boost::regex_search(line, ex_outer)) {
	i = 0;
	continue;
      }
      boost::smatch results;
      if (boost::regex_search(line, results, ex_vertices)) {
	try {
	  for (int v=0;v<3;v++) {
	    vdata[i][v] = boost::lexical_cast<double>(results[v+1]);
	  }
	}
	catch (const boost::bad_lexical_cast &blc) {
	  std::cout << "WARNING: Can't parse vertex line:" <<  line;
	  i = 10;
	  continue;
	}
	if (++i == 3) { //CREATE TRIANGLE
	  /*	  p->append_poly();
	  p->append_vertex(vdata[0][0], vdata[0][1], vdata[0][2]);
	  p->append_vertex(vdata[1][0], vdata[1][1], vdata[1][2]);
	  p->append_vertex(vdata[2][0], vdata[2][1], vdata[2][2]); */

	  facenum++;

	  //min,max
	  for(unsigned j = 0 ; j < 3 ; j ++ ) {
	    if ( XMin > vdata[j][0] ) {
	      XMin = vdata[j][0];
	    }
	    if ( XMax < vdata[j][0] ) {
	      XMax = vdata[j][0];
	    }
	    if ( YMin > vdata[j][1] ) {
	      YMin = vdata[j][1];
	    }
	    if ( YMax < vdata[j][1] ) {
	      YMax = vdata[j][1];
	    }
	    if ( ZMin > vdata[j][2] ) {
	      ZMin = vdata[j][2];
	    }
	    if ( ZMax < vdata[j][2] ) {
	      ZMax = vdata[j][2];
	    }
	  }

	  //stl layers
	  for(unsigned j = 0 ; j < 3 ; j ++ ) {
	    stlLayers[ vdata[j][2] ] = 1;
	  }

	}
      }
    }
  }
  else if (binary && !f.eof() && f.good())
    {
      f.ignore(80-5+4);
      while (1) {
	stl_facet facet;
	read_stl_facet( f, facet );
	if (f.eof()) break;

	//CREATE TRIANGLE

	facenum++;

// 	p->append_poly(); 
// 	p->append_vertex(facet.data.x1, facet.data.y1, facet.data.z1);
// 	p->append_vertex(facet.data.x2, facet.data.y2, facet.data.z2);
// 	p->append_vertex(facet.data.x3, facet.data.y3, facet.data.z3);

	//min,max
	if ( XMin > facet.data.x1 ) {
	  XMin = facet.data.x1;
	}
	if ( XMin > facet.data.x2 ) {
	  XMin = facet.data.x2;
	}
	if ( XMin > facet.data.x3 ) {
	  XMin = facet.data.x3;
	}
	if ( XMax < facet.data.x1 ) {
	  XMax = facet.data.x1;
	}
	if ( XMax < facet.data.x2 ) {
	  XMax = facet.data.x2;
	}
	if ( XMax < facet.data.x3 ) {
	  XMax = facet.data.x3;
	}

	if ( YMin > facet.data.y1 ) {
	  YMin = facet.data.y1;
	}
	if ( YMin > facet.data.y2 ) {
	  YMin = facet.data.y2;
	}
	if ( YMin > facet.data.y3 ) {
	  YMin = facet.data.y3;
	}
	if ( YMax < facet.data.y1 ) {
	  YMax = facet.data.y1;
	}
	if ( YMax < facet.data.y2 ) {
	  YMax = facet.data.y2;
	}
	if ( YMax < facet.data.y3 ) {
	  YMax = facet.data.y3;
	}

	if ( ZMin > facet.data.z1 ) {
	  ZMin = facet.data.z1;
	}
	if ( ZMin > facet.data.z2 ) {
	  ZMin = facet.data.z2;
	}
	if ( ZMin > facet.data.z3 ) {
	  ZMin = facet.data.z3;
	}
	if ( ZMax < facet.data.z1 ) {
	  ZMax = facet.data.z1;
	}
	if ( ZMax < facet.data.z2 ) {
	  ZMax = facet.data.z2;
	}
	if ( ZMax < facet.data.z3 ) {
	  ZMax = facet.data.z3;
	}

	//stl layers
	stlLayers[ facet.data.z1 ] = 1;
	stlLayers[ facet.data.z2 ] = 1;
	stlLayers[ facet.data.z3 ] = 1;

      }
    }

  std::map<double, uint32_t>::iterator stlLayer_it;
  uint32_t layers = 0, usefulLayers = 0;
  double previousLayer = -10000000.0;
  for( std::map<double, uint32_t>::iterator it = stlLayers.begin();
       it != stlLayers.end();
       ++ it ) {
    std::cout << "Layer " << layers << ": Axis Z " << it->first << std::endl;
    if ( layers > 0 ) {
      if ( minLayerHeight > (it->first - previousLayer) )  {
	std::cout << "Previous layer too thin, useless" << std::endl;
      }
      else {
	usefulLayers++;
	std::cout << "              ---> New Layer height = " << (it->first - previousLayer) << std::endl;
	previousLayer = it->first;
      }
    }
    else {
      previousLayer = it->first;
    }
    layers ++;
  }
  std::cout << "Number of layers " << layers << std::endl;
  std::cout << "Useful layers " << usefulLayers << std::endl;

  std::cout << "Face Number = " << facenum << std::endl;
  std::cout << "XMin = " << XMin << " XMax = " << XMax << ", Distance = " << (XMax - XMin) << std::endl;
  std::cout << "YMin = " << YMin << " YMax = " << YMax << ", Distance = " << (YMax - YMin) << std::endl;
  std::cout << "ZMin = " << ZMin << " ZMax = " << ZMax << ", Distance = " << (ZMax - ZMin) << std::endl;

  std::cout << "Minimum layer height = " << minLayerHeight << std::endl;
  std::cout << "Max number of layers = " << ((ZMax - ZMin)/minLayerHeight) << std::endl;

  return 0;
}

static int usage() {

  std::cout << "stl_stats filename.stl [minLayerHeight]" << std::endl;

  return -1;
}

int main(int argc, char **argv) {

  if ( argc < 2 || argc > 3 ) {
    return usage();
  }

  const char *filename = argv[1];
  double minLayerHeight = 0.3;
  if ( argc == 3 ) {
    minLayerHeight = atof(argv[2]);
  }

  return readStlFile(filename,minLayerHeight);

}

syntax highlighted by Code2HTML, v. 0.9.1

No Comments

Velleman K8200 – Rigidifier le haut du support de la vis pour Z

Il y a cette superbe pièce à imprimer directement sur thingiverse (http://www.thingiverse.com/thing:166023), quand on voit la pièce d’origine on comprend :)

Résultat: Amélioration de l’impression au niveau des couches, elles sont un peu moins visibles.

Par contre le support du Z au niveau du moteur pas à pas çà bouge …. mais bon c’est pas nouveau

No Comments

Velleman K8200 – Ventilateur horizontal et tole d’isolation

Je trouve que le montage d’origine est complètement nul, il y a une légion de “guides” pour ce ventilo sur thingiverse.

La version 0.0

A cause de ma précédente mésaventure sur l’extrudeur, çà s’est en fait transformé en opportunité. La tôle que j’ai utilisé est assez grande pour faire aussi office de support pour le ventilateur.

Je ne m’en suis pas privé et j’ai mis directement le ventilateur à souffler horizontalement.

Résultat: la qualité des impressions a bien augmenté très nettement.

Par contre, j’ai vu qu’il y avait beaucoup de variations de température au niveau de la buse.

La version 0.1

Pour contrer les grosses variations de température, j’avais encore un bout de tôle fine.

Ben oui, du coup je l’ai formé grossièrement afin de faire un guide qui n’envoie pas d’air sur la tête.

Résultat: la qualité des impressions a  augmenté légèrement et surtout il y a que très peu de variations de température au niveau de la buse.

 

No Comments

Fedora Core 20 SSD/HD Migration

Prerequisites

  1. Put the SSD/HD in your system (can be Sata or USB through a case with adaptor)
  2. Boot on the Fedora 20 and Perform a cleanup of all unneeded stuff to reduce the time spent, you don’t want to put old crap  :)
  3. IMPORTANT: Have a USB stick of at least 1 GB to put a Fedora 20 on it, in case you cannot boot …
  4. Check you have enough space on the SSD, ideally it should be less than 50% of usage.

Partitioning the HD(s)/SSD(s)

Using either fdisk on command line or gparted for a simple version, partition the disk according to the layout you want to have.

Formatting partitions

If you have a lot of small files, or the reverse a lot of huge file. It is better to perform the format on the command line to setup the size of inodes and other stuff according to the filesystem you have or you want.

Otherwise, if you don’t know just use gparted and stick to an ext4 filesystem.

Setting labels on partitions

Put at least the / mount point…

Copying content on the SSD/HD

  1. Mount the SSD/HD partitions
  2. If you use a ext2/ext3/ext4 filesystem, you can go for the simple tar method (I like it very much):
    1. tar cf – /boot | ( cd /mnt/ | tar xfp – )
    2. tar cf – /etc | (cd /mnt/ | tar xfp – )
    3. tar cf – /var | (cd /mnt/ | tar xfp – )
    4. tar cf – /root | (cd /mnt/ | tar xfp – )
    5. tar cf – /opt | (cd /mnt/ | tar xfp – )
    6. tar cf – /home | (cd /mnt | tar xfp – )
    7. tar cf – /tmp| (cd /mnt | tar xfp – )….
  3. Create empty dirs for
    1. dev
    2. mnt
    3. run
    4. sys
    5. proc
  4. Add symbolic links on / if any: it is the case on the 64 bits version

Update /etc/fstab in the target HD

Probably the new SSD(s)/HD(s) are having a new ID, you have to find it.

Personally,, I was too lazy so I used the old school way: /dev/sd[a-z][1-9]+.

Then modify the fstab on the new SSD/HD accordingly.

Setup boot loader (grub2)

  1. As root run the following commands
  2. grub2-install –recheck /dev/MYHARDDRIVE
  3. grub2-mkconfig -o /boot/grub2/grub.cfg
  4. sync
  5. reboot
  6. If the system does not boot use the USB key
    1. Mount partitions for instance in /mnt/sysimage/
    2. mount –bind /dev /mnt/sysimage/dev
    3. mount –bind /proc /mnt/sysimage/proc
    4. mount –bind /sys /mnt/sysimage/sys
    5. chroot /mnt/sysimage
    6. Then redo steps from 1. to 4. it should be ok :)

SSD Specific Tuning

  1. Check the SSD supports TRIM: sudo hdparm -I /dev/MYSSD | grep TRIM
  2. Ext4 changes in /etc/fstab add discard in options:
    1. Example: /dev/sdb1 /                       ext4    defaults,discard        1 1
  3. Avoid to swap too early, add this in /etc/sysctl.conf
     

    1. #SSD
      vm.swappiness = 0
  4. IO Scheduler change (create /etc/rc.d/rc.local and append this if existing, after enable the rc.local. Google this: “Fedora 20 rc.local” )
    #!/usr/bin/bash 

    #SSD Specific
    echo ‘noop’ > /sys/block/sdb/queue/scheduler
    echo ‘noop’ > /sys/block/sda/queue/scheduler

    exit 0

     

 

 

 

No Comments

Nurburgring 03 05 2014

No Comments

I wanna be your dog !

Je suis tombé par hasard sur les accords de “I wanna be u dog”, trop bon !

Merci la peluche

http://tabs.ultimate-guitar.com/i/iggy_pop/i_wanna_be_your_dog_tab.htm

http://www.youtube.com/watch?v=BJIqnXTqg8I

http://www.youtube.com/watch?v=eb2HwAGY6eQ

No Comments

Metallica & Alice in Chains

J’ai un peu continué à bosser:

  • One de Metallica (partie lente hein ;) )
  • Rooster d’Alice in Chains (Le solo se transpose facilement, j’ai trouvé une petite montée sympa en plus mais encore du boulot pour avoir une descente qui sonne bien)
  • Echainement d’accords un peu sympa: E Major, E minor, A, D, A (il manque la rythmique et les répétitions, mais çà sonne pas mal)
  • One Metallica (24 sur le stomplab)

No Comments

Metallica & Alice in Chains

J’ai un peu glandé ces derniers temps… (bronchite)  juste un peu de boulot sur les doigts

J’ai continué sur Master of Puppets avec cette série de vidéos :

http://www.youtube.com/watch?v=zGwwUL-PKXI

 

Jeté un oeil sur l’intro de Metallica One :

http://tabs.ultimate-guitar.com/m/metallica/one_ver2_tab.htm

 

Alice in Chains, micro solo: (corde 3)

7,6,7,9  9,7,9,6,7(down),  11,12,11

En fait, çà se transpose un peu ou on veut sur le manche

Voir là aussi:

http://tabs.ultimate-guitar.com/a/alice_in_chains/rooster_tab.htm

On peut faire une montée sur une corde au dessus, exemple sur 7,9 par contre j’ai pas encore trouvé une descente “jolie” histoire d’un peu améliorer cette bestiole

 

 

No Comments

Metallica

No Comments

Blues

  • Un peu de Blues histoire de changer
  • Bossé sur quelques accords

No Comments