X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fbase%2Fellipse.cpp;fp=src%2Fbase%2Fellipse.cpp;h=0000000000000000000000000000000000000000;hb=9f6ad3fe0b9cb30115a5d38e8af3aebed0d70c08;hp=5d4fbd5cd0895e11346228feb34aa18badcddc15;hpb=43c13b052d069ba435277d93867380d00c04931f;p=architektonas diff --git a/src/base/ellipse.cpp b/src/base/ellipse.cpp deleted file mode 100644 index 5d4fbd5..0000000 --- a/src/base/ellipse.cpp +++ /dev/null @@ -1,675 +0,0 @@ -// ellipse.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 05/28/2010 Added this text. :-) -// - -#include "ellipse.h" - -#include "drawing.h" -#include "graphicview.h" -#include "information.h" -#include "linetypepattern.h" -#include "paintinterface.h" - -/** - * Constructor. - */ -Ellipse::Ellipse(EntityContainer * parent, const EllipseData & d): - AtomicEntity(parent), data(d) -{ - //calculateEndpoints(); - calculateBorders(); -} - -/*virtual*/ Ellipse::~Ellipse() -{ -} - -/*virtual*/ Entity * Ellipse::clone() -{ - Ellipse * e = new Ellipse(*this); - e->initId(); - return e; -} - -/** @return RS2::EntityEllipse */ -/*virtual*/ RS2::EntityType Ellipse::rtti() const -{ - return RS2::EntityEllipse; -} - -/** - * @return Start point of the entity. - */ -/*virtual*/ Vector Ellipse::getStartpoint() const -{ - Vector p; - p.set(data.center.x + cos(data.angle1) * getMajorRadius(), - data.center.y + sin(data.angle1) * getMinorRadius()); - p.rotate(data.center, getAngle()); - return p; -} - -/** - * @return End point of the entity. - */ -/*virtual*/ Vector Ellipse::getEndpoint() const -{ - Vector p; - p.set(data.center.x + cos(data.angle2) * getMajorRadius(), - data.center.y + sin(data.angle2) * getMinorRadius()); - p.rotate(data.center, getAngle()); - return p; -} - -void Ellipse::moveStartpoint(const Vector & pos) -{ - data.angle1 = getEllipseAngle(pos); - //data.angle1 = data.center.angleTo(pos); - //calculateEndpoints(); - calculateBorders(); -} - -void Ellipse::moveEndpoint(const Vector & pos) -{ - data.angle2 = getEllipseAngle(pos); - //data.angle2 = data.center.angleTo(pos); - //calculateEndpoints(); - calculateBorders(); -} - -RS2::Ending Ellipse::getTrimPoint(const Vector & coord, const Vector & trimPoint) -{ - double angEl = getEllipseAngle(trimPoint); - double angM = getEllipseAngle(coord); - - if (Math::getAngleDifference(angM, angEl) > M_PI) - //if (data.reversed) { - // return RS2::EndingEnd; - //} - //else { - return RS2::EndingStart; - //} - else - //if (data.reversed) { - // return RS2::EndingStart; - //} - //else { - return RS2::EndingEnd; - //} -} - -double Ellipse::getEllipseAngle(const Vector & pos) -{ - Vector m = pos; - m.rotate(data.center, -data.majorP.angle()); - Vector v = m - data.center; - v.scale(Vector(1.0, 1.0 / data.ratio)); - return v.angle(); -} - -/** @return Copy of data that defines the ellipse. **/ -EllipseData Ellipse::getData() -{ - return data; -} - -VectorSolutions Ellipse::getRefPoints() -{ - VectorSolutions ret(getStartpoint(), getEndpoint(), data.center); - return ret; -} - -/** - * @retval true if the arc is reversed (clockwise), - * @retval false otherwise - */ -bool Ellipse::isReversed() const -{ - return data.reversed; -} - -/** sets the reversed status. */ -void Ellipse::setReversed(bool r) -{ - data.reversed = r; -} - -/** @return The rotation angle of this ellipse */ -double Ellipse::getAngle() const -{ - return data.majorP.angle(); -} - -/** @return The start angle of this arc */ -double Ellipse::getAngle1() -{ - return data.angle1; -} - -/** Sets new start angle. */ -void Ellipse::setAngle1(double a1) -{ - data.angle1 = a1; -} - -/** @return The end angle of this arc */ -double Ellipse::getAngle2() -{ - return data.angle2; -} - -/** Sets new end angle. */ -void Ellipse::setAngle2(double a2) -{ - data.angle2 = a2; -} - -/** @return The center point (x) of this arc */ -Vector Ellipse::getCenter() -{ - return data.center; -} - -/** Sets new center. */ -void Ellipse::setCenter(const Vector & c) -{ - data.center = c; -} - -/** @return The endpoint of the major axis (relative to center). */ -Vector Ellipse::getMajorP() -{ - return data.majorP; -} - -/** Sets new major point (relative to center). */ -void Ellipse::setMajorP(const Vector & p) -{ - data.majorP = p; -} - -/** @return The ratio of minor to major axis */ -double Ellipse::getRatio() -{ - return data.ratio; -} - -/** Sets new ratio. */ -void Ellipse::setRatio(double r) -{ - data.ratio = r; -} - -/** - * @return Angle length in rad. - */ -/*virtual*/ double Ellipse::getAngleLength() const -{ - if (isReversed()) - return data.angle1 - data.angle2; - else - return data.angle2 - data.angle1; -} - -/** @return The major radius of this ellipse. Same as getRadius() */ -double Ellipse::getMajorRadius() const -{ - return data.majorP.magnitude(); -} - -/** @return The minor radius of this ellipse */ -double Ellipse::getMinorRadius() const -{ - return data.majorP.magnitude() * data.ratio; -} - -/** - * Recalculates the endpoints using the angles and the radius. - */ -/* - void Ellipse::calculateEndpoints() { - double angle = data.majorP.angle(); - double radius1 = getMajorRadius(); - double radius2 = getMinorRadius(); - - startpoint.set(data.center.x + cos(data.angle1) * radius1, - data.center.y + sin(data.angle1) * radius2); - startpoint.rotate(data.center, angle); - endpoint.set(data.center.x + cos(data.angle2) * radius1, - data.center.y + sin(data.angle2) * radius2); - endpoint.rotate(data.center, angle); - } - */ - -/** - * Calculates the boundary box of this ellipse. - * - * @todo Fix that - the algorithm used is really bad / slow. - */ -void Ellipse::calculateBorders() -{ - DEBUG->print("Ellipse::calculateBorders"); - - double radius1 = getMajorRadius(); - double radius2 = getMinorRadius(); - double angle = getAngle(); - double a1 = ((!isReversed()) ? data.angle1 : data.angle2); - double a2 = ((!isReversed()) ? data.angle2 : data.angle1); - Vector startpoint = getStartpoint(); - Vector endpoint = getEndpoint(); - - double minX = std::min(startpoint.x, endpoint.x); - double minY = std::min(startpoint.y, endpoint.y); - double maxX = std::max(startpoint.x, endpoint.x); - double maxY = std::max(startpoint.y, endpoint.y); - - // kind of a brute force. TODO: exact calculation - Vector vp; - double a = a1; - - do - { - vp.set(data.center.x + radius1 * cos(a), - data.center.y + radius2 * sin(a)); - vp.rotate(data.center, angle); - - minX = std::min(minX, vp.x); - minY = std::min(minY, vp.y); - maxX = std::max(maxX, vp.x); - maxY = std::max(maxY, vp.y); - - a += 0.03; - } - while (Math::isAngleBetween(Math::correctAngle(a), a1, a2, false) - && a < 4 * M_PI); - - minV.set(minX, minY); - maxV.set(maxX, maxY); - DEBUG->print("Ellipse::calculateBorders: OK"); -} - -Vector Ellipse::getNearestEndpoint(const Vector & coord, double * dist) -{ - double dist1, dist2; - Vector nearerPoint; - Vector startpoint = getStartpoint(); - Vector endpoint = getEndpoint(); - - dist1 = startpoint.distanceTo(coord); - dist2 = endpoint.distanceTo(coord); - - if (dist2 < dist1) - { - if (dist != NULL) - *dist = dist2; - nearerPoint = endpoint; - } - else - { - if (dist != NULL) - *dist = dist1; - nearerPoint = startpoint; - } - - return nearerPoint; -} - -Vector Ellipse::getNearestPointOnEntity(const Vector & coord, bool onEntity, double * dist, Entity * * entity) -{ - DEBUG->print("Ellipse::getNearestPointOnEntity"); - - Vector ret(false); - - if (entity != NULL) - *entity = this; - double ang = getAngle(); - - Vector normalized = (coord - data.center).rotate(-ang); - - double dU = normalized.x; - double dV = normalized.y; - double dA = getMajorRadius(); - double dB = getMinorRadius(); - double dEpsilon = 1.0e-8; - int iMax = 32; - int riIFinal = 0; - double rdX = 0.0; - double rdY = 0.0; - double dDistance; - bool swap = false; - bool majorSwap = false; - - if (dA < dB) - { - double dum = dA; - dA = dB; - dB = dum; - dum = dU; - dU = dV; - dV = dum; - majorSwap = true; - } - - if (dV < 0.0) - { - dV *= -1.0; - swap = true; - } - - // initial guess - double dT = dB * (dV - dB); - - // Newton s method - int i; - - for (i = 0; i < iMax; i++) - { - DEBUG->print("Ellipse::getNearestPointOnEntity: i: %d", i); - double dTpASqr = dT + dA * dA; - double dTpBSqr = dT + dB * dB; - double dInvTpASqr = 1.0 / dTpASqr; - double dInvTpBSqr = 1.0 / dTpBSqr; - double dXDivA = dA * dU * dInvTpASqr; - double dYDivB = dB * dV * dInvTpBSqr; - double dXDivASqr = dXDivA * dXDivA; - double dYDivBSqr = dYDivB * dYDivB; - double dF = dXDivASqr + dYDivBSqr - 1.0; - DEBUG->print("Ellipse::getNearestPointOnEntity: dF: %f", dF); - - if (fabs(dF) < dEpsilon) - { - // F(t0) is close enough to zero, terminate the iteration: - rdX = dXDivA * dA; - rdY = dYDivB * dB; - riIFinal = i; - DEBUG->print("Ellipse::getNearestPointOnEntity: rdX,rdY 1: %f,%f", rdX, rdY); - break; - } - double dFDer = 2.0 * (dXDivASqr * dInvTpASqr + dYDivBSqr * dInvTpBSqr); - double dRatio = dF / dFDer; - DEBUG->print("Ellipse::getNearestPointOnEntity: dRatio: %f", dRatio); - - if (fabs(dRatio) < dEpsilon) - { - // t1-t0 is close enough to zero, terminate the iteration: - rdX = dXDivA * dA; - rdY = dYDivB * dB; - riIFinal = i; - DEBUG->print("Ellipse::getNearestPointOnEntity: rdX,rdY 2: %f,%f", rdX, rdY); - break; - } - dT += dRatio; - } - - if (i == iMax) - { - // failed to converge: - DEBUG->print("Ellipse::getNearestPointOnEntity: failed"); - dDistance = RS_MAXDOUBLE; - } - else - { - double dDelta0 = rdX - dU; - double dDelta1 = rdY - dV; - dDistance = sqrt(dDelta0 * dDelta0 + dDelta1 * dDelta1); - ret = Vector(rdX, rdY); - DEBUG->print("Ellipse::getNearestPointOnEntity: rdX,rdY 2: %f,%f", rdX, rdY); - DEBUG->print("Ellipse::getNearestPointOnEntity: ret: %f,%f", ret.x, ret.y); - } - - if (dist != NULL) - { - if (ret.valid) - *dist = dDistance; - else - *dist = RS_MAXDOUBLE; - } - - if (ret.valid) - { - if (swap) - ret.y *= -1.0; - - - if (majorSwap) - { - double dum = ret.x; - ret.x = ret.y; - ret.y = dum; - } - ret = (ret.rotate(ang) + data.center); - - if (onEntity) - { - double a1 = data.center.angleTo(getStartpoint()); - double a2 = data.center.angleTo(getEndpoint()); - double a = data.center.angleTo(ret); - - if (!Math::isAngleBetween(a, a1, a2, data.reversed)) - ret = Vector(false); - } - } - - return ret; -} - -/** - * @param tolerance Tolerance. - * - * @retval true if the given point is on this entity. - * @retval false otherwise - */ -bool Ellipse::isPointOnEntity(const Vector & coord, double tolerance) -{ - double dist = getDistanceToPoint(coord, NULL, RS2::ResolveNone); - return (dist <= tolerance); -} - -Vector Ellipse::getNearestCenter(const Vector & coord, double * dist) -{ - if (dist != NULL) - *dist = coord.distanceTo(data.center); - return data.center; -} - -/** - * @todo Implement this. - */ -Vector Ellipse::getNearestMiddle(const Vector & /*coord*/, double * dist) -{ - if (dist != NULL) - *dist = RS_MAXDOUBLE; - return Vector(false); -} - -Vector Ellipse::getNearestDist(double /*distance*/, const Vector & /*coord*/, double * dist) -{ - if (dist != NULL) - *dist = RS_MAXDOUBLE; - return Vector(false); -} - -double Ellipse::getDistanceToPoint(const Vector & coord, Entity * * entity, RS2::ResolveLevel, double /*solidDist*/) -{ - double dist = RS_MAXDOUBLE; - getNearestPointOnEntity(coord, true, &dist, entity); - - return dist; -} - -void Ellipse::move(Vector offset) -{ - data.center.move(offset); - //calculateEndpoints(); - calculateBorders(); -} - -void Ellipse::rotate(Vector center, double angle) -{ - data.center.rotate(center, angle); - data.majorP.rotate(angle); - //calculateEndpoints(); - calculateBorders(); -} - -void Ellipse::scale(Vector center, Vector factor) -{ - data.center.scale(center, factor); - data.majorP.scale(factor); - //calculateEndpoints(); - calculateBorders(); -} - -/** - * @todo deal with angles correctly - */ -void Ellipse::mirror(Vector axisPoint1, Vector axisPoint2) -{ - Vector mp = data.center + data.majorP; - - data.center.mirror(axisPoint1, axisPoint2); - mp.mirror(axisPoint1, axisPoint2); - - data.majorP = mp - data.center; - - double a = axisPoint1.angleTo(axisPoint2); - - Vector vec; - vec.setPolar(1.0, data.angle1); - vec.mirror(Vector(0.0, 0.0), axisPoint2 - axisPoint1); - data.angle1 = vec.angle() - 2 * a; - - vec.setPolar(1.0, data.angle2); - vec.mirror(Vector(0.0, 0.0), axisPoint2 - axisPoint1); - data.angle2 = vec.angle() - 2 * a; - - data.reversed = (!data.reversed); - - //calculateEndpoints(); - calculateBorders(); -} - -void Ellipse::moveRef(const Vector & ref, const Vector & offset) -{ - Vector startpoint = getStartpoint(); - Vector endpoint = getEndpoint(); - - if (ref.distanceTo(startpoint) < 1.0e-4) - moveStartpoint(startpoint + offset); - - - if (ref.distanceTo(endpoint) < 1.0e-4) - moveEndpoint(endpoint + offset); -} - -void Ellipse::draw(PaintInterface * painter, GraphicView * view, double /*patternOffset*/) -{ - if (!painter || !view) - return; - - if (getPen().getLineType() == RS2::SolidLine || isSelected() - || view->getDrawingMode() == RS2::ModePreview) - painter->drawEllipse(view->toGui(getCenter()), - getMajorRadius() * view->getFactor().x, - getMinorRadius() * view->getFactor().x, - getAngle(), getAngle1(), getAngle2(), isReversed()); - else - { - double styleFactor = getStyleFactor(view); - - if (styleFactor < 0.0) - { - painter->drawEllipse(view->toGui(getCenter()), - getMajorRadius() * view->getFactor().x, - getMinorRadius() * view->getFactor().x, - getAngle(), getAngle1(), getAngle2(), isReversed()); - return; - } - - // Pattern: - LineTypePattern * pat; - - if (isSelected()) - pat = &patternSelected; - else - pat = view->getPattern(getPen().getLineType()); - - if (pat == NULL) - return; - - // Pen to draw pattern is always solid: - Pen pen = painter->getPen(); - pen.setLineType(RS2::SolidLine); - painter->setPen(pen); - - double * da; // array of distances in x. - int i; // index counter - - double length = getAngleLength(); - - // create pattern: - da = new double[pat->num]; - - double tot = 0.0; - i = 0; - bool done = false; - double curA = getAngle1(); - double curR; - Vector cp = view->toGui(getCenter()); - double r1 = getMajorRadius() * view->getFactor().x; - double r2 = getMinorRadius() * view->getFactor().x; - - do - { - curR = sqrt(Math::pow(getMinorRadius() * cos(curA), 2.0) - + Math::pow(getMajorRadius() * sin(curA), 2.0)); - - if (curR > 1.0e-6) - { - da[i] = fabs(pat->pattern[i] * styleFactor) / curR; - - if (pat->pattern[i] * styleFactor > 0.0) - { - if (tot + fabs(da[i]) < length) - painter->drawEllipse(cp, r1, r2, getAngle(), curA, curA + da[i], false); - else - painter->drawEllipse(cp, r1, r2, getAngle(), curA, getAngle2(), false); - } - } - - curA += da[i]; - tot += fabs(da[i]); - done = tot > length; - - i++; - - if (i >= pat->num) - i = 0; - } - while (!done); - - delete[] da; - } -} - -/** - * Dumps the point's data to stdout. - */ -std::ostream & operator<<(std::ostream & os, const Ellipse & a) -{ - os << " Ellipse: " << a.data << "\n"; - return os; -} -