static char *sccs_id= (sccs_id, "@(#)LineShape.c	3.6 7/28/92");

//$LineShape$
#include "Class.h"
#include "LineShape.h"
#include "DrawView.h"

//---- LineShape Methods -------------------------------------------------------

static short LineImage[]= {
#   include  "images/LineShape.im"
};

MetaImpl(LineShape, (T(p1), T(p2),
0));

LineShape::LineShape()
{
}

short *LineShape::GetImage()
{
    return LineImage;
}


float LineShape::GetLength() const
{
    return GeoDist(gp1, gp2);
}

Rectangle LineShape::GetSpan()
{
    return Rectangle(p1, p2);
}

void LineShape::SetSpan(Rectangle r)
{
    gp1= p1= r.origin;
    gp2= p2= r.extent;
    Shape::SetSpan(r);
}

void LineShape::Moveby(Point delta)
{
    gp1= p1+= delta;
    gp2= p2+= delta;
    Shape::Moveby(delta);
}

void LineShape::AreaChanged()
{
    p1= gp1;
    p2= gp2;
    Shape::AreaChanged();
}

void LineShape::Flip(int n)
{
    int t;
    GeoPos tg;
    float tf;
    
    switch (n) {
    case 1:     // vertical
	t= p1.y; tf= gp1.Lat;
	p1.y= p2.y; gp1.Lat= gp2.Lat;
	p2.y= t; gp2.Lat= tf;
	break;
    case 2:     // horizontal
	t= p1.x; tf= gp1.Long;
	p1.x= p2.x; gp1.Long= gp2.Long;
	p2.x= t; gp2.Long= tf;
	break;
    case 3:
	Swap(p1, p2);
	tg= gp1; gp1= gp2; gp2= tg;
	break;  // horizontal & vertical
    default:
	return;
    }
    Changed();
}


void LineShape::Init(Point pp1, Point pp2)
{
    gp1= GeoPos(this, pp1);
    gp2= GeoPos(this, pp2);
    Shape::Init(p1= pp1, p2= pp2);
}

int LineShape::PointOnHandle(Point p)
{
#if 0
    int n= Shape::PointOnHandle(p);
    if (n == 0)
	return 0;
    if (n == 1)
	return 7;
    return -1;
#else
    return Shape::PointOnHandle(p);
#endif
}

Rectangle LineShape::InvalRect()
{
    if (arrows != eDefaultCap)
	return bbox.Expand(Max(HandleSize,Point(4*pensize))/2+1);
    return bbox.Expand(Max(HandleSize,Point(pensize))/2+1);
}

Point *LineShape::MakeHandles(int *n)
{
#if 0
    spts[0]= p1-bbox.origin;
    spts[1]= p2-bbox.origin;
    *n= 2;
    return spts;
#else
    return Shape::MakeHandles(n);
#endif
}

Point LineShape::GetConnectionPoint(Point p)
{
#if 1
    if (p == gPoint0)
	return Shape::GetConnectionPoint(p);
    if (Length(p1-p) < Length(p2-p))
	return p1;
    return p2;
#else
    return Shape::GetConnectionPoint(0);
#endif
}

Point LineShape::Chop(Point p)
{
#if 0
    return p;
#else
    if (Length(p1-p) < Length(p2-p))
	return p1;
    return p2;
    // return Shape::GetConnectionPoint(0);
#endif
}

Rectangle LineShape::GetTextRect()
{
    if (p1.x == p2.x)       // vertical
	return Rectangle(bbox.Center(), 0).Expand(Point(50, 0));
	
    if (p1.y == p2.y) {     // horizontal
	Rectangle r= bbox;
	r.origin= p1;
	r.origin.y+= 10;
	return r;
    }
    return Shape::GetTextRect();                    
}

bool LineShape::ContainsPoint(Point p)
{
    return PointAtLine(p, p1, p2);
}

void LineShape::Outline(Point pp1, Point pp2)
{
#if 1
    // Shape::Outline(pp1, pp2);
    GrStrokeRect(NormRect(pp1, pp2));
#else
    GrLine(pp1, pp2);
#endif
}

void LineShape::Draw(Rectangle)
{
    GrLine(p1, p2);
}


bool LineShape::PointAtLine(Point p, Point p1, Point p2)
{
    int dx= p2.x - p1.x, dy= p2.y - p1.y, a1, a2;
    Point delta= Max(HandleSize,Point(pensize))/2+1;
    
    if (! NormRect(p1, p2).Expand(delta).ContainsPoint(p))
	return FALSE;

    if (dx == 0 || dy == 0)
	return TRUE;
	
    a1= (dy*(p.x-p1.x)/dx)+p1.y-p.y;
    a2= (dx*(p.y-p1.y)/dy)+p1.x-p.x;
    
    return abs(a1) <= delta.x || abs(a2) <= delta.y;
}

#ifdef ET25
OStream& LineShape::PrintOn(OStream& s)
#else
ostream& LineShape::PrintOn(ostream& s)
#endif
{
    Shape::PrintOn(s);
    s << p1 SP << p2 SP;
    gp1.Save(s);
    return gp2.Save(s);
}

#ifdef ET25
IStream& LineShape::ReadFrom(IStream& s)
#else
istream& LineShape::ReadFrom(istream& s)
#endif
{
    Shape::ReadFrom(s);
    s >> p1 >> p2;
    gp1.Load(s);
    gp2.Load(s);
    return s;
}
