X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fbase%2Finformation.cpp;fp=src%2Fbase%2Finformation.cpp;h=0000000000000000000000000000000000000000;hb=9f6ad3fe0b9cb30115a5d38e8af3aebed0d70c08;hp=4838f97c1129673ae4eebafd440656b9775b6592;hpb=43c13b052d069ba435277d93867380d00c04931f;p=architektonas diff --git a/src/base/information.cpp b/src/base/information.cpp deleted file mode 100644 index 4838f97..0000000 --- a/src/base/information.cpp +++ /dev/null @@ -1,825 +0,0 @@ -// information.cpp -// -// Part of the Architektonas Project -// Originally part of QCad Community Edition by Andrew Mustun -// Extensively rewritten and refactored by James L. Hammons -// Portions copyright (C) 2001-2003 RibbonSoft -// Copyright (C) 2010 Underground Software -// See the README and GPLv2 files for licensing and warranty information -// -// JLH = James L. Hammons -// -// Who When What -// --- ---------- ----------------------------------------------------------- -// JLH 06/01/2010 Added this text. :-) -// - -#include "information.h" - -#include "constructionline.h" -#include "debug.h" - -/** - * Default constructor. - * - * @param container The container to which we will add - * entities. Usually that's an Drawing entity but - * it can also be a polyline, text, ... - */ -Information::Information(EntityContainer& container) -{ - this->container = &container; -} - -/** - * @return true: if the entity is a dimensioning enity. - * false: otherwise - */ -bool Information::isDimension(RS2::EntityType type) -{ - if (type == RS2::EntityDimAligned || type == RS2::EntityDimLinear - || type == RS2::EntityDimRadial || type == RS2::EntityDimDiametric - || type == RS2::EntityDimAngular) - { - return true; - } - else - { - return false; - } -} - -/** - * @retval true the entity can be trimmed. - * i.e. it is in a graphic or in a polyline. - */ -bool Information::isTrimmable(Entity * e) -{ - if (e) - { - if (e->getParent()) - { - if (e->getParent()->rtti() == RS2::EntityPolyline) - { - return true; - } - else if (e->getParent()->rtti() == RS2::EntityContainer - || e->getParent()->rtti() == RS2::EntityDrawing - || e->getParent()->rtti() == RS2::EntityBlock) - { - // normal entity: - return true; - } - } - } - - return false; -} - -/** - * @retval true the two entities can be trimmed to each other; - * i.e. they are in a graphic or in the same polyline. - */ -bool Information::isTrimmable(Entity * e1, Entity * e2) -{ - if (e1 && e2) - { - if (e1->getParent() && e2->getParent()) - { - if (e1->getParent()->rtti() == RS2::EntityPolyline - && e2->getParent()->rtti() == RS2::EntityPolyline - && e1->getParent()==e2->getParent()) - { - // in the same polyline - EntityContainer * pl = e1->getParent(); - int idx1 = pl->findEntity(e1); - int idx2 = pl->findEntity(e2); - DEBUG->print("Information::isTrimmable: idx1: %d, idx2: %d", idx1, idx2); - - if (abs(idx1 - idx2) == 1 || abs(idx1 - idx2) == pl->count() - 1) - { - // directly following entities - return true; - } - else - { - // not directly following entities - return false; - } - } - else if ((e1->getParent()->rtti() == RS2::EntityContainer - || e1->getParent()->rtti() == RS2::EntityDrawing - || e1->getParent()->rtti() == RS2::EntityBlock) - && (e2->getParent()->rtti() == RS2::EntityContainer - || e2->getParent()->rtti() == RS2::EntityDrawing - || e2->getParent()->rtti() == RS2::EntityBlock)) - { - // normal entities: - return true; - } - } - else - { - // independent entities with the same parent: - return (e1->getParent() == e2->getParent()); - } - } - - return false; -} - -/** - * Gets the nearest end point to the given coordinate. - * - * @param coord Coordinate (typically a mouse coordinate) - * - * @return the coordinate found or an invalid vector - * if there are no elements at all in this graphics - * container. - */ -Vector Information::getNearestEndpoint(const Vector & coord, double * dist) const -{ - return container->getNearestEndpoint(coord, dist); -} - -/** - * Gets the nearest point to the given coordinate which is on an entity. - * - * @param coord Coordinate (typically a mouse coordinate) - * @param dist Pointer to a double which will contain the - * measured distance after return or NULL - * @param entity Pointer to a pointer which will point to the - * entity on which the point is or NULL - * - * @return the coordinate found or an invalid vector - * if there are no elements at all in this graphics - * container. - */ -Vector Information::getNearestPointOnEntity(const Vector & coord, - bool onEntity, double * dist, Entity ** entity) const -{ - return container->getNearestPointOnEntity(coord, onEntity, dist, entity); -} - -/** - * Gets the nearest entity to the given coordinate. - * - * @param coord Coordinate (typically a mouse coordinate) - * @param dist Pointer to a double which will contain the - * masured distance after return - * @param level Level of resolving entities. - * - * @return the entity found or NULL if there are no elements - * at all in this graphics container. - */ -Entity * Information::getNearestEntity(const Vector & coord, - double * dist, RS2::ResolveLevel level) const -{ - return container->getNearestEntity(coord, dist, level); -} - -/** - * Calculates the intersection point(s) between two entities. - * - * @param onEntities true: only return intersection points which are - * on both entities. - * false: return all intersection points. - * - * @todo support more entities - * - * @return All intersections of the two entities. The tangent flag in - * VectorSolutions is set if one intersection is a tangent point. - */ -VectorSolutions Information::getIntersection(Entity * e1, - Entity * e2, bool onEntities) -{ - VectorSolutions ret; - double tol = 1.0e-4; - - if (!e1 || !e2) - return ret; - - // unsupported entities / entity combinations: - if ((e1->rtti() == RS2::EntityEllipse && e2->rtti() == RS2::EntityEllipse) - || e1->rtti() == RS2::EntityText || e2->rtti() == RS2::EntityText - || isDimension(e1->rtti()) || isDimension(e2->rtti())) - { - return ret; - } - - // (only) one entity is an ellipse: - if (e1->rtti() == RS2::EntityEllipse || e2->rtti() == RS2::EntityEllipse) - { - if (e2->rtti() == RS2::EntityEllipse) - { - Entity * tmp = e1; - e1 = e2; - e2 = tmp; - } - - if (e2->rtti() == RS2::EntityLine) - { - Ellipse * ellipse = (Ellipse *)e1; - ret = getIntersectionLineEllipse((Line *)e2, ellipse); - tol = 1.0e-1; - } - // ellipse / arc, ellipse / ellipse: not supported: - else - { - return ret; - } - } - else - { - Entity * te1 = e1; - Entity * te2 = e2; - - // entity copies - so we only have to deal with lines and arcs - Line l1(NULL, LineData(Vector(0.0, 0.0), Vector(0.0, 0.0))); - Line l2(NULL, LineData(Vector(0.0, 0.0), Vector(0.0, 0.0))); - - Arc a1(NULL, ArcData(Vector(0.0, 0.0), 1.0, 0.0, 2 * M_PI, false)); - Arc a2(NULL, ArcData(Vector(0.0, 0.0), 1.0, 0.0, 2 * M_PI, false)); - - // convert construction lines to lines: - if (e1->rtti() == RS2::EntityConstructionLine) - { - ConstructionLine * cl = (ConstructionLine *)e1; - l1.setStartpoint(cl->getPoint1()); - l1.setEndpoint(cl->getPoint2()); - te1 = &l1; - } - - if (e2->rtti() == RS2::EntityConstructionLine) - { - ConstructionLine * cl = (ConstructionLine *)e2; - l2.setStartpoint(cl->getPoint1()); - l2.setEndpoint(cl->getPoint2()); - te2 = &l2; - } - - // convert circles to arcs: - if (e1->rtti() == RS2::EntityCircle) - { - Circle * c = (Circle *)e1; - ArcData data(c->getCenter(), c->getRadius(), 0.0, 2 * M_PI, false); - a1.setData(data); - te1 = &a1; - } - - if (e2->rtti() == RS2::EntityCircle) - { - Circle * c = (Circle *)e2; - ArcData data(c->getCenter(), c->getRadius(), 0.0, 2 * M_PI, false); - a2.setData(data); - te2 = &a2; - } - - // line / line: - // - //else - if (te1->rtti() == RS2::EntityLine && te2->rtti() == RS2::EntityLine) - { - Line * line1 = (Line *)te1; - Line * line2 = (Line *)te2; - ret = getIntersectionLineLine(line1, line2); - } - // line / arc: - // - else if (te1->rtti() == RS2::EntityLine && te2->rtti() == RS2::EntityArc) - { - Line * line = (Line *)te1; - Arc * arc = (Arc *)te2; - ret = getIntersectionLineArc(line, arc); - } - // arc / line: - // - else if (te1->rtti() == RS2::EntityArc && te2->rtti() == RS2::EntityLine) - { - Arc * arc = (Arc *)te1; - Line * line = (Line *)te2; - ret = getIntersectionLineArc(line, arc); - } - // arc / arc: - // - else if (te1->rtti() == RS2::EntityArc && te2->rtti() == RS2::EntityArc) - { - Arc * arc1 = (Arc *)te1; - Arc * arc2 = (Arc *)te2; - ret = getIntersectionArcArc(arc1, arc2); - } - else - { - DEBUG->print("Information::getIntersection:: Unsupported entity type."); - } - } - - // Check all intersection points for being on entities: - // - if (onEntities) - { - if (!e1->isPointOnEntity(ret.get(0), tol) || !e2->isPointOnEntity(ret.get(0), tol)) - { - ret.set(0, Vector(false)); - } - - if (!e1->isPointOnEntity(ret.get(1), tol) || !e2->isPointOnEntity(ret.get(1), tol)) - { - ret.set(1, Vector(false)); - } - - if (!e1->isPointOnEntity(ret.get(2), tol) || !e2->isPointOnEntity(ret.get(2), tol)) - { - ret.set(2, Vector(false)); - } - - if (!e1->isPointOnEntity(ret.get(3), tol) || !e2->isPointOnEntity(ret.get(3), tol)) - { - ret.set(3, Vector(false)); - } - } - - int k = 0; - for(int i=0; i<4; ++i) - { - if (ret.get(i).valid) - { - ret.set(k, ret.get(i)); - k++; - } - } - - for (int i=k; i<4; ++i) - { - ret.set(i, Vector(false)); - } - - return ret; -} - -/** - * @return Intersection between two lines. - */ -VectorSolutions Information::getIntersectionLineLine(Line * e1, Line * e2) -{ - VectorSolutions ret; - - if (!e1 || !e2) - return ret; - - Vector p1 = e1->getStartpoint(); - Vector p2 = e1->getEndpoint(); - Vector p3 = e2->getStartpoint(); - Vector p4 = e2->getEndpoint(); - - double num = ((p4.x - p3.x) * (p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x)); - double div = ((p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y)); - - if (fabs(div) > RS_TOLERANCE) - { - double u = num / div; - double xs = p1.x + u * (p2.x - p1.x); - double ys = p1.y + u * (p2.y - p1.y); - ret = VectorSolutions(Vector(xs, ys)); - } - // lines are parallel - else - ret = VectorSolutions(); - - return ret; -} - -/** - * @return One or two intersection points between given entities. - */ -VectorSolutions Information::getIntersectionLineArc(Line * line, Arc * arc) -{ - VectorSolutions ret; - - if (line==NULL || arc==NULL) { - return ret; - } - - double dist=0.0; - Vector nearest; - nearest = line->getNearestPointOnEntity(arc->getCenter(), false, &dist); - - // special case: arc touches line (tangent): - if (fabs(dist - arc->getRadius()) < 1.0e-4) { - ret = VectorSolutions(nearest); - ret.setTangent(true); - return ret; - } - - Vector p = line->getStartpoint(); - Vector d = line->getEndpoint() - line->getStartpoint(); - if (d.magnitude()<1.0e-6) { - return ret; - } - - Vector c = arc->getCenter(); - double r = arc->getRadius(); - Vector delta = p - c; - - // root term: - double term = Math::pow(Vector::dotP(d, delta), 2.0) - - Math::pow(d.magnitude(), 2.0) - * (Math::pow(delta.magnitude(), 2.0) - Math::pow(r, 2.0)); - - // no intersection: - if (term<0.0) { - VectorSolutions s; - ret = s; - } - - // one or two intersections: - else { - double t1 = (- Vector::dotP(d, delta) + sqrt(term)) - / Math::pow(d.magnitude(), 2.0); - double t2; - bool tangent = false; - - // only one intersection: - if (fabs(term)getCenter(); - Vector c2 = e2->getCenter(); - - double r1 = e1->getRadius(); - double r2 = e2->getRadius(); - - Vector u = c2 - c1; - - // concentric - if (u.magnitude()<1.0e-6) { - return ret; - } - - Vector v = Vector(u.y, -u.x); - - double s, t1, t2, term; - - s = 1.0/2.0 * ((r1*r1 - r2*r2)/(Math::pow(u.magnitude(), 2.0)) + 1.0); - - term = (r1*r1)/(Math::pow(u.magnitude(), 2.0)) - s*s; - - // no intersection: - if (term<0.0) { - ret = VectorSolutions(); - } - - // one or two intersections: - else { - t1 = sqrt(term); - t2 = -sqrt(term); - bool tangent = false; - - Vector sol1 = c1 + u*s + v*t1; - Vector sol2 = c1 + u*s + v*t2; - - if (sol1.distanceTo(sol2)<1.0e-4) { - sol2 = Vector(false); - ret = VectorSolutions(sol1); - tangent = true; - } else { - ret = VectorSolutions(sol1, sol2); - } - - ret.setTangent(tangent); - } - - return ret; -} - -/** - * @return One or two intersection points between given entities. - */ -VectorSolutions Information::getIntersectionLineEllipse(Line * line, Ellipse * ellipse) -{ - VectorSolutions ret; - - if (line==NULL || ellipse==NULL) { - return ret; - } - - // rotate into normal position: - double ang = ellipse->getAngle(); - - double rx = ellipse->getMajorRadius(); - double ry = ellipse->getMinorRadius(); - Vector center = ellipse->getCenter(); - Vector a1 = line->getStartpoint().rotate(center, -ang); - Vector a2 = line->getEndpoint().rotate(center, -ang); - Vector origin = a1; - Vector dir = a2-a1; - Vector diff = origin - center; - Vector mDir = Vector(dir.x/(rx*rx), dir.y/(ry*ry)); - Vector mDiff = Vector(diff.x/(rx*rx), diff.y/(ry*ry)); - - double a = Vector::dotP(dir, mDir); - double b = Vector::dotP(dir, mDiff); - double c = Vector::dotP(diff, mDiff) - 1.0; - double d = b*b - a*c; - - if (d < 0) { - DEBUG->print("Information::getIntersectionLineEllipse: outside 0"); - } else if ( d > 0 ) { - double root = sqrt(d); - double t_a = (-b - root) / a; - double t_b = (-b + root) / a; - - /*if ( (t_a < 0 || 1 < t_a) && (t_b < 0 || 1 < t_b) ) { - if ( (t_a < 0 && t_b < 0) || (t_a > 1 && t_b > 1) ) { - DEBUG->print("Information::getIntersectionLineEllipse: outside 1"); - } - else { - DEBUG->print("Information::getIntersectionLineEllipse: inside 1"); - } - } else {*/ - DEBUG->print("Information::getIntersectionLineEllipse: intersection 1"); - Vector ret1(false); - Vector ret2(false); - //if ( 0 <= t_a && t_a <= 1 ) { - //DEBUG->print("Information::getIntersectionLineEllipse: 0<=t_a<=1"); - ret1 = a1.lerp(a2, t_a); - DEBUG->print("Information::getIntersectionLineEllipse: ret1: %f/%f", ret1.x, ret1.y); - //} - //if ( 0 <= t_b && t_b <= 1 ) { - //DEBUG->print("Information::getIntersectionLineEllipse: 0<=t_b<=1"); - ret2 = a1.lerp(a2, t_b); - DEBUG->print("Information::getIntersectionLineEllipse: ret2: %f/%f", ret2.x, ret2.y); - //} - if (ret1.valid && ret2.valid) { - ret = VectorSolutions(ret1, ret2); - } - else { - if (ret1.valid) { - ret = VectorSolutions(ret1); - } - if (ret2.valid) { - ret = VectorSolutions(ret2); - } - } - //} - } else { - double t = -b/a; - if ( 0 <= t && t <= 1 ) { - DEBUG->print("Information::getIntersectionLineEllipse: 0<=t<=1"); - DEBUG->print("Information::getIntersectionLineEllipse: intersection 2"); - ret = VectorSolutions(a1.lerp(a2, t)); - DEBUG->print("Information::getIntersectionLineEllipse: ret1: %f/%f", ret.get(0).x, ret.get(0).y); - } else { - DEBUG->print("Information::getIntersectionLineEllipse: outside 2"); - } - } - - ret.rotate(center, ang); - return ret; - - - - /* - Arc* arc = new Arc(NULL, - ArcData(ellipse->getCenter(), - ellipse->getMajorRadius(), - ellipse->getAngle1(), - ellipse->getAngle2(), - false)); - Line* other = (Line*)line->clone(); - double angle = ellipse->getAngle(); - //double ratio = ellipse->getRatio(); - - // rotate entities: - other->rotate(ellipse->getCenter(), -angle); - other->scale(ellipse->getCenter(), Vector(1.0, 1.0/ellipse->getRatio())); - - ret = getIntersectionLineArc(other, arc); - - ret.scale(ellipse->getCenter(), Vector(1.0, ellipse->getRatio())); - ret.rotate(ellipse->getCenter(), angle); - - delete arc; - delete other; - - return ret; - */ -} - -/** - * Checks if the given coordinate is inside the given contour. - * - * @param point Coordinate to check. - * @param contour One or more entities which shape a contour. - * If the given contour is not closed, the result is undefined. - * The entities don't need to be in a specific order. - * @param onContour Will be set to true if the given point it exactly - * on the contour. - */ -bool Information::isPointInsideContour(const Vector & point, - EntityContainer * contour, bool * onContour) -{ - if (contour==NULL) { - DEBUG->print(Debug::D_WARNING, - "Information::isPointInsideContour: contour is NULL"); - return false; - } - - if (point.x < contour->getMin().x || point.x > contour->getMax().x || - point.y < contour->getMin().y || point.y > contour->getMax().y) - return false; - - double width = contour->getSize().x+1.0; - bool sure; - int counter; - int tries = 0; - double rayAngle = 0.0; - - do - { - sure = true; - - // create ray: - Vector v; - v.setPolar(width*10.0, rayAngle); - Line ray(NULL, LineData(point, point+v)); - counter = 0; - VectorSolutions sol; - - if (onContour) - *onContour = false; - - for(Entity * e=contour->firstEntity(RS2::ResolveAll); e!=NULL; - e=contour->nextEntity(RS2::ResolveAll)) - { - // intersection(s) from ray with contour entity: - sol = Information::getIntersection(&ray, e, true); - - for(int i=0; i<=1; ++i) - { - Vector p = sol.get(i); - - if (p.valid) - { - // point is on the contour itself - if (p.distanceTo(point) < 1.0e-5) - { - if (onContour) - { - *onContour = true; - } - } - else - { - if (e->rtti() == RS2::EntityLine) - { - Line * line = (Line *)e; - - // ray goes through startpoint of line: - if (p.distanceTo(line->getStartpoint()) < 1.0e-4) - { - if (Math::correctAngle(line->getAngle1()) < M_PI) - { - counter++; - sure = false; - } - } - // ray goes through endpoint of line: - else if (p.distanceTo(line->getEndpoint()) < 1.0e-4) - { - if (Math::correctAngle(line->getAngle2()) < M_PI) - { - counter++; - sure = false; - } - } - // ray goes through the line: - else - { - counter++; - } - } - else if (e->rtti() == RS2::EntityArc) - { - Arc * arc = (Arc *)e; - - if (p.distanceTo(arc->getStartpoint()) < 1.0e-4) - { - double dir = arc->getDirection1(); - - if ((dir < M_PI && dir >= 1.0e-5) - || ((dir > 2 * M_PI - 1.0e-5 || dir < 1.0e-5) - && arc->getCenter().y > p.y)) - { - counter++; - sure = false; - } - } - else if (p.distanceTo(arc->getEndpoint()) < 1.0e-4) - { - double dir = arc->getDirection2(); - - if ((dir < M_PI && dir >= 1.0e-5) - || ((dir > 2 * M_PI - 1.0e-5 || dir < 1.0e-5) - && arc->getCenter().y>p.y)) - { - counter++; - sure = false; - } - } - else - { - counter++; - } - } - else if (e->rtti() == RS2::EntityCircle) - { - // tangent: - if (i == 0 && sol.get(1).valid == false) - { - if (!sol.isTangent()) - { - counter++; - } - else - { - sure = false; - } - } - else if (i == 1 || sol.get(1).valid) - { - counter++; - } - } - } - } - } - } - - rayAngle += 0.02; - tries++; - } - while (!sure && rayAngle < 2 * M_PI && tries < 6); - - // remove double intersections: - /* - Q3PtrList is2; - bool done; - Vector* av; - do { - done = true; - double minDist = RS_MAXDOUBLE; - double dist; - av = NULL; - for (Vector* v = is.first(); v!=NULL; v = is.next()) { - dist = point.distanceTo(*v); - if (dist