Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
c5721c306This file is pinned to the selected release. Download the original to open it in your design tool.
// HEllipse.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.
#include "stdafx.h"
#include "HEllipse.h"
#include "HLine.h"
#include "HILine.h"
#include "HArc.h"
#include "HPoint.h"
#include "Gripper.h"
#include "GripData.h"
#include "OCCProperty.h"
//static
int HEllipse::m_type = 0;
HEllipse::HEllipse(const HEllipse &e){
operator=(e);
}
HEllipse::HEllipse(){
}
HEllipse::HEllipse(const gp_Elips &e, const HeeksColor* col) :color(*col){
C = e.Location();
m_start = 0;
m_end = 2 * M_PI;
SetEllipse(e);
}
HEllipse::HEllipse(const gp_Elips &e, double start, double end, const HeeksColor* col):color(*col){
m_start = start; m_end = end;
C = e.Location();
SetEllipse(e);
}
HEllipse::~HEllipse(){
}
const HEllipse& HEllipse::operator=(const HEllipse &e){
HeeksObj::operator =(e);
m_start = e.m_start; m_end = e.m_end;
color = e.color;
C = e.C;
SetEllipse(e.GetEllipse());
return *this;
}
const wchar_t* HEllipse::GetIconFilePath()
{
static std::wstring iconpath = theApp->GetResFolder() + L"/icons/ellipse.png";
return iconpath.c_str();
}
//segments - number of segments per full revolution!
void HEllipse::GetSegments(void(*callbackfunc)(const double *p), double pixels_per_mm, bool want_start_point)const
{
gp_Dir x_axis = m_xdir;
gp_Dir y_axis = m_zdir ^ m_xdir;
gp_Pnt centre = C;
double radius = m_majr;
double min_radius = m_minr;
double ratio = min_radius/radius;
gp_Pnt zp(0,0,0);
gp_Dir up(0,0,1);
double end_angle = m_end;
double start_angle = m_start;
double d_angle = end_angle - start_angle;
if(fabs(d_angle) < TOLERANCE)
d_angle = 2*M_PI;
if(d_angle < 0)
d_angle += 2*M_PI;
int segments = (int)(fabs(pixels_per_mm * radius * d_angle / (2*M_PI) + 1));
if(segments > 1000)
segments = 1000;
double theta = d_angle / (double)segments;
while(theta>1.0){segments*=2;theta = d_angle / (double)segments;}
double tangetial_factor = tan(theta);
double radial_factor = 1 - cos(theta);
double x = radius * cos(start_angle);
double y = radius * sin(start_angle);
double pp[3];
for(int i = 0; i < segments + 1; i++)
{
gp_Pnt p = centre.XYZ() + x * x_axis.XYZ() + y * y_axis.XYZ() * ratio;
extract(p, pp);
(*callbackfunc)(pp);
double tx = -y;
double ty = x;
x += tx * tangetial_factor;
y += ty * tangetial_factor;
double rx = - x;
double ry = - y;
x += rx * radial_factor;
y += ry * radial_factor;
}
}
static void glVertexFunction(const double *p){glVertex3d(p[0], p[1], p[2]);}
void HEllipse::glCommands(bool select, bool marked, bool no_color){
if(!no_color){
theApp->glColorEnsuringContrast(color);
}
GLfloat save_depth_range[2];
if(marked){
glGetFloatv(GL_DEPTH_RANGE, save_depth_range);
glDepthRange(0, 0);
glLineWidth(2);
}
glBegin(GL_LINE_STRIP);
GetSegments(glVertexFunction, theApp->GetPixelScale());
glEnd();
if(marked){
glLineWidth(1);
glDepthRange(save_depth_range[0], save_depth_range[1]);
}
}
HeeksObj *HEllipse::MakeACopy(void)const{
HEllipse *new_object = new HEllipse(*this);
return new_object;
}
void HEllipse::Transform(const Matrix &m){
gp_Trsf mat = make_matrix(m.e);
SetEllipse(GetEllipse().Transformed(mat));
}
void HEllipse::GetBox(CBox &box){
gp_Elips m_ellipse = GetEllipse();
gp_Dir x_axis = m_ellipse.XAxis().Direction();
gp_Dir y_axis = m_ellipse.YAxis().Direction();
gp_XYZ c = m_ellipse.Location().XYZ();
gp_XYZ x = x_axis.XYZ() * m_ellipse.MajorRadius();
gp_XYZ y = y_axis.XYZ() * m_ellipse.MinorRadius();
gp_Pnt p[4];
p[0] = gp_Pnt(c - x - y);
p[1] = gp_Pnt(c + x - y);
p[2] = gp_Pnt(c + x + y);
p[3] = gp_Pnt(c - x + y);
for(int i = 0; i<4; i++)
{
double pp[3];
extract(p[i], pp);
box.Insert(pp);
}
}
void HEllipse::GetGripperPositions(std::list<GripData> *list, bool just_for_endof){
gp_Elips m_ellipse = GetEllipse();
if(!just_for_endof)
{
gp_Dir x_axis = m_ellipse.XAxis().Direction();
gp_Dir y_axis = m_ellipse.YAxis().Direction();
gp_XYZ c = m_ellipse.Location().XYZ();
double maj_r = m_ellipse.MajorRadius();
double min_r = m_ellipse.MinorRadius();
gp_Pnt maj_s(c + x_axis.XYZ() * maj_r);
gp_Pnt min_s(c + y_axis.XYZ() * min_r);
gp_Pnt rot(c+x_axis.XYZ() * maj_r * -1);
list->push_back(GripData(GripperTypeStretch, Point3d(maj_s.X(), maj_s.Y(), maj_s.Z()), &m_majr));
list->push_back(GripData(GripperTypeStretch,Point3d(min_s.X(),min_s.Y(),min_s.Z()),&m_minr));
list->push_back(GripData(GripperTypeStretch, Point3d(c.X(), c.Y(), c.Z()), (void*)&C));
list->push_back(GripData(GripperTypeRotate, Point3d(rot.X(), rot.Y(), rot.Z()), NULL));
}
}
static void on_set_centre(const double *vt, HeeksObj* object){
((HEllipse*)object)->C = make_point(vt);
theApp->Repaint();
}
static void on_set_axis(const double *vt, HeeksObj* object){
HEllipse *e = (HEllipse*)object;
gp_Ax2 a(e->C,e->m_zdir,e->m_xdir);
a.SetDirection(make_vector(vt));
e->m_zdir = a.Direction();
e->m_xdir = a.XDirection();
theApp->Repaint();
}
static void on_set_major_radius(double value, HeeksObj* object){
((HEllipse*)object)->m_majr = value;
theApp->Repaint();
}
static void on_set_minor_radius(double value, HeeksObj* object){
((HEllipse*)object)->m_minr = value;
theApp->Repaint();
}
static void on_set_rotation(double value, HeeksObj* object){
((HEllipse*)object)->SetRotation(value);
theApp->Repaint();
}
static void on_set_start_angle(double value, HeeksObj* object){
((HEllipse*)object)->m_start = value;
theApp->Repaint();
}
static void on_set_end_angle(double value, HeeksObj* object){
((HEllipse*)object)->m_end = value;
theApp->Repaint();
}
void HEllipse::SetRotation(double value)
{
gp_Dir up(0, 0, 1);
gp_Pnt zp(0,0,0);
double rot = GetRotation();
gp_Ax2 a(C,m_zdir,m_xdir);
a.Rotate(gp_Ax1(C,up),value-rot);
m_zdir = a.Direction();
m_xdir = a.XDirection();
}
double HEllipse::GetRotation()const
{
return GetEllipseRotation(GetEllipse());
}
void HEllipse::GetProperties(std::list<Property *> *list){
double rot = GetRotation();
list->push_back(PropertyGp<gp_Pnt>(this, L"Centre", &C));
list->push_back(PropertyGp<gp_Dir>(this, L"axis", &m_zdir));
list->push_back(new PropertyLength(this, L"major radius", &m_majr));
list->push_back(new PropertyLength(this, L"minor radius", &m_minr));
list->push_back(new PropertyDouble(this, L"rotation", (const double*)&rot));
list->push_back(new PropertyDouble(this, L"start angle", &m_start));
list->push_back(new PropertyDouble(this, L"end angle", &m_end));
HeeksObj::GetProperties(list);
}
bool HEllipse::FindNearPoint(const double* ray_start, const double* ray_direction, double *point){
gp_Lin ray(make_point(ray_start), make_vector(ray_direction));
std::list< gp_Pnt > rl;
ClosestPointsLineAndEllipse(ray, GetEllipse(), rl);
if(rl.size()>0)
{
extract(rl.front(), point);
return true;
}
return false;
}
bool HEllipse::FindPossTangentPoint(const double* ray_start, const double* ray_direction, double *point){
// any point on this ellipse is a possible tangent point
return FindNearPoint(ray_start, ray_direction, point);
}
bool HEllipse::Stretch(const double *p, const double* shift, void* data){
//TODO:
// 1. When the major and minor axis swap, the unused handle switches sides.
// 2. The handle switches to the other radius if you go past M_PI/4
gp_Pnt vp = make_point(p);
gp_Pnt zp(0,0,0);
gp_Dir up(0, 0, 1);
gp_Vec vshift = make_vector(shift);
double rot = GetRotation();
gp_Dir x_axis = m_xdir;
gp_Dir y_axis = m_zdir ^ m_xdir;
gp_Pnt c = C;
double maj_r = m_majr;
double min_r = m_minr;
gp_Pnt maj_s(c.XYZ() + x_axis.XYZ() * maj_r);
gp_Pnt min_s(c.XYZ() + y_axis.XYZ() * min_r);
gp_Pnt np = vp.XYZ() + vshift.XYZ();
#if 0
// these cause compiler warnings, so I have commented them out
double d = c.Distance(np);
double f = DistanceToFoci(np,m_ellipse)/2;
#endif
if(data == &C){
C = np;
}
else if(data == &m_majr || data == &m_minr)
{
//We have to rotate the incoming vector to be in our coordinate system
gp_Pnt cir = np.XYZ() - c.XYZ();
cir.Rotate(gp_Ax1(zp,up),-rot);
//This is shockingly simple
if( data == (void*)1)
{
double nradius = 1/sqrt((1-(1/min_r)*(1/min_r)*cir.X()*cir.X()) / cir.Y() / cir.Y());
if(nradius > 1 / TOLERANCE || nradius != nradius)
nradius = 1 / TOLERANCE;
if(nradius > min_r)
m_majr = nradius;
else
{
m_majr = min_r;
m_minr = nradius;
SetRotation(GetRotation()-M_PI/2);
m_start += M_PI/2;
m_end += M_PI/2;
}
}
else
{
double nradius = 1/sqrt((1-(1/maj_r)*(1/maj_r)*cir.Y()*cir.Y()) / cir.X() / cir.X());
if(nradius > 1 / TOLERANCE || nradius != nradius)
nradius = 1 / TOLERANCE;
if(nradius < maj_r)
m_minr = nradius;
else
{
m_minr = maj_r;
m_majr = nradius;
SetRotation(GetRotation()+M_PI/2);
m_start-=M_PI/2;
m_end-=M_PI/2;
}
}
}
return false;
}
bool HEllipse::GetCentrePoint(double* pos)
{
extract(C, pos);
return true;
}
void HEllipse::WriteToXML(TiXmlElement *element)
{
element->SetAttribute("col", color.COLORREF_color());
element->SetDoubleAttribute("maj", m_majr);
element->SetDoubleAttribute("min", m_minr);
element->SetDoubleAttribute("rot", GetRotation());
element->SetDoubleAttribute("cx", C.X());
element->SetDoubleAttribute("cy", C.Y());
element->SetDoubleAttribute("cz", C.Z());
gp_Dir D = m_zdir;
element->SetDoubleAttribute("ax", D.X());
element->SetDoubleAttribute("ay", D.Y());
element->SetDoubleAttribute("az", D.Z());
element->SetDoubleAttribute("start", m_start);
element->SetDoubleAttribute("end", m_end);
HeeksObj::WriteToXML(element);
}
void HEllipse::ReadFromXML(TiXmlElement *pElem)
{
m_xdir = gp_Dir(0, 1, 0);
double zdir[3] = { 0, 0, 1 };
int att_col;
double x;
if(pElem->Attribute("col", &att_col))color = HeeksColor((long)att_col);
pElem->Attribute("maj", &m_majr);
pElem->Attribute("min", &m_minr);
if (pElem->Attribute("rot", &m_rot))
{
// set x axis from rotation
m_xdir.Rotate(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), m_rot);
}
pElem->Attribute("start", &m_start);
pElem->Attribute("end", &m_end);
pElem->Attribute("ax", &zdir[0]);
pElem->Attribute("ay", &zdir[1]);
pElem->Attribute("az", &zdir[2]);
m_zdir = gp_Dir(zdir[0], zdir[1], zdir[2]);
if(pElem->Attribute("cx", &x))C.SetX(x);
if(pElem->Attribute("cy", &x))C.SetY(x);
if(pElem->Attribute("cz", &x))C.SetZ(x);
else
{
// try the version where the centre point was a child
for(TiXmlElement* pElem2 = TiXmlHandle(pElem).FirstChildElement().Element(); pElem2; pElem2 = pElem2->NextSiblingElement())
{
HeeksObj* object = theApp->ReadXMLElement(pElem2);
if(object->GetType() == PointType)
{
C = P2G(((HPoint*)object)->m_p);
delete object;
break;
}
delete object;
}
}
HeeksObj::ReadFromXML(pElem);
}
void HEllipse::SetEllipse(const gp_Elips &e)
{
C = e.Location();
m_zdir = e.Axis().Direction();
m_xdir = e.XAxis().Direction();
m_majr = e.MajorRadius();
m_minr = e.MinorRadius();
}
gp_Elips HEllipse::GetEllipse() const
{
return gp_Elips(gp_Ax2(C,m_zdir,m_xdir),m_majr,m_minr);
}
int HEllipse::Intersects(const HeeksObj *object, std::list< double > *rl)const
{
int numi = 0;
#if 0
// to do
gp_Elips m_ellipse = GetEllipse();
switch(object->GetType())
{
case SketchType:
return( ((CSketch *)object)->Intersects( this, rl ));
case LineType:
{
std::list<gp_Pnt> plist;
intersect(((HLine*)object)->GetLine(), m_ellipse, plist);
for(std::list<gp_Pnt>::iterator It = plist.begin(); It != plist.end(); It++)
{
gp_Pnt& pnt = *It;
if(((HLine*)object)->Intersects(pnt))
{
if(rl)add_pnt_to_doubles(pnt, *rl);
numi++;
}
}
}
break;
case ILineType:
{
std::list<gp_Pnt> plist;
intersect(((HILine*)object)->GetLine(), m_ellipse, plist);
if(rl)convert_pnts_to_doubles(plist, *rl);
numi += plist.size();
}
break;
/* case ArcType:
{
std::list<gp_Pnt> plist;
intersect(m_ellipse, ((HArc*)object)->m_circle, plist);
for(std::list<gp_Pnt>::iterator It = plist.begin(); It != plist.end(); It++)
{
gp_Pnt& pnt = *It;
if(((HArc*)object)->Intersects(pnt))
{
if(rl)add_pnt_to_doubles(pnt, *rl);
numi++;
}
}
}
break;
case CircleType:
{
std::list<gp_Pnt> plist;
intersect(m_ellipse, ((HEllipse*)object)->m_circle, plist);
if(rl)convert_pnts_to_doubles(plist, *rl);
numi += plist.size();
}
break; */
}
#endif
return numi;
}