/* $Id$
*
* Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com).
*
* This file is part of OpenCAMlib
* (see https://github.com/aewallin/opencamlib).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef MILLING_CUTTER_H
#define MILLING_CUTTER_H
#include
#include
#include
#include "stlsurf.hpp"
#include "fiber.hpp"
#include "point.hpp"
#include "clpoint.hpp"
#include "ccpoint.hpp"
namespace ocl
{
class Triangle;
class STLSurf;
// CC_CLZ_Pair is the return type of
// CC is the x-coordinate of the cutter-contact point
// CLZ is the z-coordinate of the cutter-location point
typedef std::pair< double, double > CC_CLZ_Pair;
typedef std::pair< double, double > DoublePair;
///
/// \brief MillingCutter is a base-class for all milling cutters
///
class MillingCutter {
friend class CompositeCutter;
public:
/// default constructor
MillingCutter() {}
virtual ~MillingCutter() {}
/// return the diameter of the cutter
inline double getDiameter() const { return diameter; }
/// return the radius of the cutter
inline double getRadius() const { return radius; }
/// return the length of the cutter
inline double getLength() const { return length; }
/// return a MillingCutter which is larger than *this by d
virtual MillingCutter* offsetCutter(double d) const;
/// \brief Test if the cutter bounding-box, positioned at cl,
/// overlaps with the bounding-box of Triangle t.
/// works in the xy-plane
bool overlaps(Point &cl, const Triangle &t) const;
/// \brief drop cutter at (cl.x, cl.y) against the three vertices of Triangle t.
/// calls this->height(r) on the subclass of MillingCutter we are using.
/// if cl.z is too low, updates cl.z so that cutter does not cut any vertex.
bool vertexDrop(CLPoint &cl, const Triangle &t) const;
/// \brief drop cutter at (cl.x, cl.y) against facet of Triangle t
/// calls xy_normal_length(), normal_length(), and center_height() on the subclass.
/// if cl.z is too low, updates cl.z so that cutter does not cut the facet.
/// CompositeCutter may be the only sub-class that needs to reimplement this function.
virtual bool facetDrop(CLPoint &cl, const Triangle &t) const;
/// \brief drop cutter at (cl.x, cl.y) against the three edges of input Triangle t.
/// calls the sub-class MillingCutter::singleEdgeDrop on each edge
/// if cl.z is too low, updates cl.z so that cutter does not cut any edge.
virtual bool edgeDrop(CLPoint& cl, const Triangle &t) const;
/// \brief drop the MillingCutter at Point cl down along the z-axis until it makes contact with Triangle t.
/// This function calls vertexDrop, facetDrop, and edgeDrop to do its job.
/// Follows the template-method, or "self-delegation" design pattern.
/// if cl.z is too low, updates cl.z so that the cutter does not cut Triangle t.
bool dropCutter(CLPoint &cl, const Triangle &t) const;
/// \brief call dropCutter on all Triangles in an STLSurf
/// drops the MillingCutter at Point cl down along the z-axis
/// until it makes contact with a triangle in the STLSurf s
/// NOTE: no kd-tree optimization, this function will make
/// dropCutter() calls for each and every Triangle in s.
/// NOTE: should not really be used for real work, demo/debug only
bool dropCutterSTL(CLPoint &cl, const STLSurf &s) const;
/// push cutter along Fiber f against Triangle t by calling vertexPush, facetPush, and edgePush
/// Interval i will be updated so that it contains the interval where the cutter
/// would violate/gouge the Triangle.
/// Return true if contact was made with the Triangle
bool pushCutter(const Fiber& f, Interval& i, const Triangle& t) const;
/// return a string representation of the MillingCutter
virtual std::string str() const {return "MillingCutter (all derived classes should override this)";}
protected:
// PUSH-CUTTER
/// push the cutter along Fiber f into contact with the vertices of Triangle t
/// updates Interval i with the interfering/gouging interval.
/// calls singleVertexPush() on the three vertices of Triangle t
virtual bool vertexPush(const Fiber& f, Interval& i, const Triangle& t) const;
/// push cutter against a single vertex p
bool singleVertexPush(const Fiber& f, Interval& i, const Point& p, CCType cctyp) const;
/// push cutter along Fiber f into contact with facet of Triangle t, and update Interval i
/// calls generalFacetPush()
virtual bool facetPush(const Fiber& f, Interval& i, const Triangle& t) const;
/// push cutter with given normal/center/xy_length into contact with Triangle facet
bool generalFacetPush( double normal_length,
double center_height,
double xy_normal_length,
const Fiber& fib,
Interval& i,
const Triangle& t)
const;
/// push cutter along Fiber f into contact with edges of Triangle t, update Interval i.
/// calls singleEdgePush() on all three edges of Triangle t.
/// return true if a contact with an edge was found
virtual bool edgePush(const Fiber& f, Interval& i, const Triangle& t) const;
/// push cutter along fiber against a single edge p1-p2
/// calls horizEdgePush(), shaftEdgePush(), and generalEdgePush()
bool singleEdgePush(const Fiber& f, Interval& i, const Point& p1, const Point& p2) const;
/// push-cutter horizontal edge case
/// horizontal are much simpler than the general case.
/// we can consider the cutter circular with an effective radius of this->width(h)
bool horizEdgePush(const Fiber& f, Interval& i, const Point& p1, const Point& p2) const;
/// push-cutter cylindrical shaft case.
/// This is called when the contact is above the sphere/toroid/cone shaped lower part of the cutter
bool shaftEdgePush(const Fiber& f, Interval& i, const Point& p1, const Point& p2) const;
/// when horizEdgePush and shaftEdgePush fail we must call this general edge-push function.
/// here we do not assume that the p1-p2 edge is oriented in a special direction
virtual bool generalEdgePush(const Fiber& f,
Interval& i,
const Point& p1,
const Point& p2) const {
return false;
}
/// CCPoint calculation and interval update for push-cutter
bool calcCCandUpdateInterval( double t, double ccv, const Point& q, const Point& p1, const Point& p2,
const Fiber& f, Interval& i, double height, CCType cctyp) const;
// DROP-CUTTER
/// drop cutter against edge p1-p2 at xy-distance d from cl
/// translates to cl=(0,0) and rotates edge to be along x-axis
/// for call to singleEdgeDropCanonical()
bool singleEdgeDrop(CLPoint& cl, const Point& p1, const Point& p2, double d) const;
/// edge-drop in the 'canonical' position with cl=(0,0,cl.z) and edge u1-u2 along x-axis.
/// returns x-coordinate of cc-point and cl.z as a CC_CLZ_Pair.
/// must be implemented in a subclass.
virtual CC_CLZ_Pair singleEdgeDropCanonical(const Point& u1,
const Point& u2) const {
return CC_CLZ_Pair(0.0,0.0); // dummy return value, better to throw an exception or assert?
}
// HEIGHT / WIDTH
/// return the height of the cutter at radius r. redefine in subclass.
virtual double height(double r) const {assert(0); return -1;}
/// return the width of the cutter at height h. redefine in subclass.
virtual double width(double h) const {assert(0); return -1;}
// DATA
/// xy_normal length that locates the cutter center relative to a cc-point on a facet.
double xy_normal_length;
/// normal length that locates the cutter center relative to a cc-point on a facet.
double normal_length;
/// height of cutter center along z-axis
double center_height;
/// diameter of cutter
double diameter;
/// radius of cutter
double radius;
/// length of cutter
double length;
};
} // end namespace
#endif
// end file millingcutter.h