Esempio n. 1
0
void REllipse::moveEndPoint(const RVector& pos, bool changeAngleOnly) {
    if (changeAngleOnly) {
        endParam = getParamTo(pos);
    }
    else {
        RVector sp = getStartPoint();
        double distOri = sp.getDistanceTo(getEndPoint());
        double angleOri = sp.getAngleTo(getEndPoint());
        if (distOri<RS::PointTolerance) {
            return;
        }

        double distNew = sp.getDistanceTo(pos);
        double angleNew = sp.getAngleTo(pos);
        double factor = distNew / distOri;
        if (factor<RS::PointTolerance) {
            return;
        }
        double angleDelta = angleNew - angleOri;

        center.scale(factor, sp);
        center.rotate(angleDelta, sp);
        majorPoint.scale(factor);
        majorPoint.rotate(angleDelta);
    }
}
Esempio n. 2
0
/**
 * \overload
 */
RRefPoint RGraphicsView::getClosestReferencePoint(REntity::Id entityId, const RVector& screenPosition) {
    RRefPoint ret = RVector::invalid;
    double minDist = RMAXDOUBLE;

    if (scene == NULL) {
        return ret;
    }

    if (getDocument() == NULL) {
        return ret;
    }
    QSharedPointer<REntity> entity = getDocument()->queryEntity(entityId);
    if (entity.isNull()) {
        return ret;
    }

    QList<RRefPoint> referencePoints = entity->getReferencePoints(scene->getProjectionRenderingHint());
    QList<RRefPoint>::iterator it;
    for (it=referencePoints.begin(); it!=referencePoints.end(); it++) {
        RVector rp = mapToView(*it);

        double dist = screenPosition.getDistanceTo(rp);
        if (dist<minDist) {
            minDist = dist;
            ret = (*it);
        }
    }

    return ret;
}
Esempio n. 3
0
/**
 * Creates an arc from 3 points.
 */
RArc RArc::createFrom3Points(const RVector& startPoint,
                              const RVector& point,
                              const RVector& endPoint) {
    // intersection of two middle lines

    // middle points between first two points:
    RVector mp1 = RVector::getAverage(startPoint, point);
    double a1 = startPoint.getAngleTo(point) + M_PI / 2.0;
    // direction from middle point to center:
    RVector dir1 = RVector::createPolar(1.0, a1);

    // middle points between last two points:
    RVector mp2 = RVector::getAverage(point, endPoint);
    double a2 = point.getAngleTo(endPoint) + M_PI / 2.0;
    // direction from middle point to center:
    RVector dir2 = RVector::createPolar(1.0, a2);

    RLine midLine1(mp1, mp1 + dir1);
    RLine midLine2(mp2, mp2 + dir2);

    QList<RVector> ips = midLine1.getIntersectionPoints(midLine2, false);
    if (ips.length()!=1) {
        //this.error = qsTr("No arc possible");
        return RArc();
    }

    RVector center = ips[0];
    double radius = center.getDistanceTo(endPoint);
    double angle1 = center.getAngleTo(startPoint);
    double angle2 = center.getAngleTo(endPoint);
    bool reversed = RMath::isAngleBetween(center.getAngleTo(point),
                                            angle1, angle2, true);

    return RArc(center, radius, angle1, angle2, reversed);
}
Esempio n. 4
0
RCircle RCircle::createFrom3Points(const RVector& p1,
                                  const RVector& p2,
                                  const RVector& p3) {
    // intersection of two middle lines

    // middle points between first two points:
    RVector mp1 = RVector::getAverage(p1, p2);
    double a1 = p1.getAngleTo(p2) + M_PI / 2.0;
    // direction from middle point to center:
    RVector dir1 = RVector::createPolar(1.0, a1);

    // middle points between last two points:
    RVector mp2 = RVector::getAverage(p2, p3);
    double a2 = p2.getAngleTo(p3) + M_PI / 2.0;
    // direction from middle point to center:
    RVector dir2 = RVector::createPolar(1.0, a2);

    RLine midLine1(mp1, mp1 + dir1);
    RLine midLine2(mp2, mp2 + dir2);

    QList<RVector> ips = midLine1.getIntersectionPoints(midLine2, false);
    if (ips.length()!=1) {
        return RCircle();
    }

    RVector center = ips[0];
    double radius = center.getDistanceTo(p3);
//    double angle1 = center.getAngleTo(p1);
//    double angle2 = center.getAngleTo(p3);
//    bool reversed = RMath::isAngleBetween(center.getAngleTo(p2),
//                                            angle1, angle2, true);

    return RCircle(center, radius);
}
Esempio n. 5
0
/**
 * Creates an arc from its startpoint, endpoint and bulge (= tan(angle/4)).
 */
RArc RArc::createFrom2PBulge(const RVector& startPoint,
        const RVector& endPoint, double bulge) {

    RArc arc;

    arc.reversed = (bulge < 0.0);
    double alpha = atan(bulge) * 4.0;

    RVector middle = (startPoint + endPoint) / 2.0;
    double dist = startPoint.getDistanceTo(endPoint) / 2.0;

    // alpha can't be 0.0 at this point
    arc.radius = fabs(dist / sin(alpha / 2.0));

    double wu = fabs(RMath::pow(arc.radius, 2.0) - RMath::pow(dist, 2.0));
    double h = sqrt(wu);
    double angle = startPoint.getAngleTo(endPoint);

    if (bulge > 0.0) {
        angle += M_PI / 2.0;
    } else {
        angle -= M_PI / 2.0;
    }

    if (fabs(alpha) > M_PI) {
        h *= -1.0;
    }

    arc.center.setPolar(h, angle);
    arc.center += middle;
    arc.startAngle = arc.center.getAngleTo(startPoint);
    arc.endAngle = arc.center.getAngleTo(endPoint);

    return arc;
}
Esempio n. 6
0
bool RSpline::isOnShape(const RVector& point, bool limited, double tolerance) const {
    if (hasProxy()) {
        double t = getTAtPoint(point);
        RVector p = getPointAt(t);
        return point.getDistanceTo(p) < tolerance;
    }
    else {
        return RShape::isOnShape(point, limited, tolerance);
    }
}
Esempio n. 7
0
QSharedPointer<RShape> RCircle::getTransformed(const QTransform& transform) const {
    RVector ct = center.getTransformed2d(transform);
    RVector sp = center + RVector(radius, 0);
    RVector spt = sp.getTransformed2d(transform);

    return QSharedPointer<RShape>(
        new RCircle(
            ct,
            ct.getDistanceTo(spt)
        )
    );
}
Esempio n. 8
0
bool RDimDiametricData::moveReferencePoint(const RVector& referencePoint,
        const RVector& targetPoint) {

    bool ret = false;

    if (referencePoint.equalsFuzzy(chordPoint)) {
        RVector c = (definitionPoint + chordPoint)/2.0;
        double d = c.getDistanceTo(chordPoint);
        double a = c.getAngleTo(targetPoint);

        RVector v = RVector::createPolar(d, a);
        chordPoint = c + v;
        definitionPoint = c - v;

        autoTextPos = true;
        ret = true;
    }
    else if (referencePoint.equalsFuzzy(definitionPoint)) {
        RVector c = (definitionPoint + chordPoint)/2.0;
        double d = c.getDistanceTo(definitionPoint);
        double a = c.getAngleTo(targetPoint);

        RVector v = RVector::createPolar(d, a);
        definitionPoint = c + v;
        chordPoint = c - v;

        autoTextPos = true;
        ret = true;
    }

    if (!ret) {
        ret = RDimensionData::moveReferencePoint(referencePoint, targetPoint);
    }

    if (ret) {
        update();
    }

    return ret;
}
Esempio n. 9
0
/**
 * Maps the given model position to the grid.
 */
RVector ROrthoGrid::snapToGrid(const RVector& positionUcs) {
    RDocumentInterface* documentInterface = view.getDocumentInterface();
    if (documentInterface==NULL) {
        return RVector::invalid;
    }

    RVector sp = spacing;
    if (!sp.isValid()) {
        sp = metaSpacing;
        if (isometric) {
            sp /= 2;
        }
    }

    int x = RMath::mround(positionUcs.x / sp.x);
    int y = RMath::mround(positionUcs.y / sp.y);
    int z = RMath::mround(positionUcs.z / sp.z);

    // closest grid point is not available in isometric grid,
    // find closest available grid point:
    if (isometric && (x+y)%2!=0) {
        int cx, cy;
        double minDist = RMAXDOUBLE;
        double dist;
        for (int ix=-1; ix<=1; ix++) {
            for (int iy=-1; iy<=1; iy++) {
                if (qAbs(ix) + qAbs(iy)!=1) {
                    continue;
                }
                cx = RMath::mround(positionUcs.x / sp.x) + ix;
                cy = RMath::mround(positionUcs.y / sp.y) + iy;
                dist = positionUcs.getDistanceTo(RVector(cx*sp.x, cy*sp.y));
                if (dist<minDist) {
                    x = cx;
                    y = cy;
                    minDist = dist;
                }
            }
        }
    }

    RVector gridPositionUcs = RVector(
        x * sp.x,
        y * sp.y,
        z * sp.z
    );

    RUcs ucs = documentInterface->getCurrentUcs();
    return ucs.mapFromUcs(gridPositionUcs);
}
Esempio n. 10
0
/**
 * \return Closest point to \c point on this entity. Used for snap to
 *        points on entity.
 */
RVector REntityData::getClosestPointOnEntity(const RVector& point,
    double range, bool limited) const {

    Q_UNUSED(range)

    RVector ret = RVector::invalid;
    double minDist = RMAXDOUBLE;
    QList<QSharedPointer<RShape> > shapes = getShapes();
    for (int i=0; i<shapes.size(); i++) {
        RVector r = shapes.at(i)->getClosestPointOnShape(point, limited);
        double dist = r.getDistanceTo(point);
        if (!ret.isValid() || dist<minDist) {
            ret = r;
            minDist = dist;
        }
    }
    return ret;
}
Esempio n. 11
0
void RSpline::removeFitPointAt(const RVector& point) {
    double minDist = RMAXDOUBLE;
    int index = -1;
    for (int i=0; i<fitPoints.length(); i++) {
        double dist = point.getDistanceTo(fitPoints[i]);
        if (dist<minDist) {
            minDist = dist;
            index = i;
        }
    }

    if (index<0 || index>=fitPoints.length()) {
        return;
    }

    fitPoints.removeAt(index);
    update();
}
Esempio n. 12
0
/**
 * Finds the reference point that is the closest to the given screen
 * coordinate (in pixels).
 *
 * \param range Maximum distance in pixels.
 *
 * \return The closest referecene point in model coordinates.
 */
RRefPoint RGraphicsView::getClosestReferencePoint(const RVector& screenPosition, int range) {
    RRefPoint ret = RVector::invalid;
    if (scene == NULL) {
        return ret;
    }

    double minDist = (double) range;

    QMultiMap<REntity::Id, RRefPoint>& referencePoints = scene->getReferencePoints();
    QMultiMap<REntity::Id, RRefPoint>::iterator it;
    for (it = referencePoints.begin(); it != referencePoints.end(); it++) {
        RVector rp = mapToView(*it);

        double dist = screenPosition.getDistanceTo(rp);
        if (dist < minDist) {
            minDist = dist;
            ret = *it;
        }
    }

    return ret;
}
Esempio n. 13
0
/**
 * \todo Not working as expected, fix or disable
 */
QSharedPointer<RShape> RArc::getTransformed(const QTransform& transform) const {
    RVector ct = center.getTransformed2d(transform);
    RVector sp = getStartPoint();
    RVector spt = sp.getTransformed2d(transform);
    RVector ep = getEndPoint();
    RVector ept = ep.getTransformed2d(transform);
    //RVector mp = getMiddlePoint();
    //RVector mpt = mp.getTransformed2d(transform);

    RArc* ret = new RArc(
            ct,
            ct.getDistanceTo(spt),
            ct.getAngleTo(spt),
            ct.getAngleTo(ept),
            reversed
        );

//    if (!ret->getMiddlePoint().equalsFuzzy(mpt)) {
//        ret->setReversed(!reversed);
//    }

    return QSharedPointer<RShape>(ret);
}
Esempio n. 14
0
void REventHandler::drawSnapLabel(QPainter* painter, const RVector& pos, const RVector& posRestriction, const QString& text) {
    RVector p = graphicsView->mapToView(pos);
    RVector pr = RVector::invalid;
    if (posRestriction.isValid()) {
        pr = graphicsView->mapToView(posRestriction);
    }
    RColor color = RSettings::getColor("GraphicsViewColors/TextLabelColor", RColor(249,198,31));
    painter->setPen(color);

    QFont font = RSettings::getSnapLabelFont();
    font.setPointSizeF(font.pointSizeF()*graphicsView->getDevicePixelRatio());
    QFontMetrics fm(font);
    painter->setFont(font);

    int offset = 5 * graphicsView->getDevicePixelRatio();

    if (!text.isEmpty()) {
        painter->drawText(
            p.x + offset, p.y + offset,
            fm.width(text)+10, fm.height()+10,
            Qt::AlignHCenter | Qt::AlignVCenter,
            text, NULL);
    }

    painter->drawEllipse(p.x-offset, p.y-offset, offset*2, offset*2);

    // restriction position:
    if (pr.isSane()) {
        painter->drawLine(pr.x, pr.y-offset, pr.x+offset, pr.y);
        painter->drawLine(pr.x+offset, pr.y, pr.x, pr.y+offset);
        painter->drawLine(pr.x, pr.y+offset, pr.x-offset, pr.y);
        painter->drawLine(pr.x-offset, pr.y, pr.x, pr.y-offset);
    }

    // display distance/angle:
    int display = RSettings::getIntValue("DisplaySettings/DisplayDistanceAngle", 0);
    if (display == 0) {
        return;
    }

    RDocumentInterface* di = graphicsView->getDocumentInterface();
    RDocument* doc = graphicsView->getDocument();

    RVector relativeZero = di->getRelativeZero();

    double dist, angle;
    if (posRestriction.isSane()) {
        dist = relativeZero.getDistanceTo(posRestriction);
        angle = relativeZero.getAngleTo(posRestriction);
    } else {
        dist = relativeZero.getDistanceTo(pos);
        angle = relativeZero.getAngleTo(pos);
    }

    int lp = doc->getLinearPrecision();
    QString distStr = RUnit::doubleToString(dist, lp);

    angle = RMath::rad2deg(angle);
    int ap = doc->getAnglePrecision();
    QString angStr = RUnit::doubleToString(angle, ap);

    QString sep = RSettings::getStringValue("Input/PolarCoordinateSeparator", "<");

    color = RSettings::getColor("GraphicsViewColors/MeasurementToolsColor", RColor(155,220,112));
    painter->setPen(color);
    QString displayText;
    switch (display) {
    case 0:
        displayText = "";
        break;
    case 1:
        displayText = distStr + sep + angStr + QChar(0x00b0);
        break;
    case 2:
        displayText = distStr;
        break;
    case 3:
        displayText = angStr + QChar(0x00b0);
        break;
    default:
        displayText = "";
    }

    if (!displayText.isEmpty()) {
        painter->drawText(
                    p.x + offset, p.y - 3*offset - fm.height(),
                    fm.width(displayText)+10, fm.height()+10,
                    Qt::AlignHCenter | Qt::AlignVCenter,
                    displayText, NULL);
    }
}
Esempio n. 15
0
RCircle RCircle::createFrom2Points(const RVector& p1, const RVector& p2) {
    RVector center = (p1+p2)/2.0;
    double radius = p1.getDistanceTo(p2)/2.0;
    return RCircle(center, radius);
}
Esempio n. 16
0
bool RCircle::contains(const RVector& p) const {
    return p.getDistanceTo(center) < radius;
    // TODO: + RS::PointTolerance ?
}
Esempio n. 17
0
/**
 * Creates a dimensioning line (line with one, two or no arrows).
 */
QList<QSharedPointer<RShape> > RDimensionData::getDimensionLineShapes(
    const RVector& p1, const RVector& p2,
    bool arrow1, bool arrow2) const {

    QList<QSharedPointer<RShape> > ret;

    // text height (DIMTXT)
    double dimtxt = getDimtxt();
    // text distance to line (DIMGAP)
    double dimgap = getDimgap();

    // length of dimension line:
    dimLineLength = p1.getDistanceTo(p2);

    // do we have to put the arrows outside of the line?
    bool outsideArrows = (dimLineLength < getDimasz()*2.5);

    // arrow angles:
    double arrowAngle1, arrowAngle2;

    // Create dimension line:
    RLine dimensionLine(p1, p2);

    if (outsideArrows==false) {
        arrowAngle1 = dimensionLine.getDirection2();
        arrowAngle2 = RMath::getNormalizedAngle(arrowAngle1+M_PI);
    } else {
        arrowAngle1 = dimensionLine.getDirection1();
        arrowAngle2 = RMath::getNormalizedAngle(arrowAngle1+M_PI);

        // extend dimension line outside arrows
        RVector dir;
        dir.setPolar(getDimasz()*2, arrowAngle2);
        dimensionLine.setStartPoint(p1 + dir);
        dimensionLine.setEndPoint(p2 - dir);
    }

    ret.append(QSharedPointer<RShape>(new RLine(dimensionLine)));

    if (arrow1) {
        QList<QSharedPointer<RShape> > arrow = getArrow(p1, arrowAngle1);
        ret.append(arrow);
    }

    if (arrow2) {
        QList<QSharedPointer<RShape> > arrow = getArrow(p2, arrowAngle2);
        ret.append(arrow);
    }

    double dimAngle1 = dimensionLine.getDirection1();
    bool corrected=false;
    defaultAngle = RMath::makeAngleReadable(dimAngle1, true, &corrected);

    if (autoTextPos) {
        RVector newTextPos = dimensionLine.getMiddlePoint();
        RVector distV;

        // rotate text so it's readable from the bottom or right (ISO)
        // quadrant 1 & 4
        if (corrected) {
            distV.setPolar(dimgap + dimtxt/2.0, dimAngle1-M_PI/2.0);
        } else {
            distV.setPolar(dimgap + dimtxt/2.0, dimAngle1+M_PI/2.0);
        }

        // move text away from dimension line:
        newTextPos+=distV;

        textPositionCenter = newTextPos;
    }

    return ret;
}
Esempio n. 18
0
RVector RSnapIntersection::snap(
    const RVector& position,
    RGraphicsView& view,
    const QMap<REntity::Id, QSet<int> >& candidates,
    const RBox& queryBox) {

    RDocument* document = view.getDocument();
    if (document==NULL) {
        return lastSnap;
    }

    REntity::Id entityId1 = REntity::INVALID_ID;
    REntity::Id entityId2 = REntity::INVALID_ID;
    lastSnap = RVector::invalid;
    double minDist = RMAXDOUBLE;
    double dist;

    QMap<REntity::Id, QSet<int> >::const_iterator it1;
    for (it1=candidates.begin(); it1!=candidates.end(); it1++) {
        if (RMouseEvent::hasMouseMoved()) {
            lastSnap = RVector::invalid;
            return RVector::invalid;
        }
        QSharedPointer<REntity> e1 = document->queryEntityDirect(it1.key());
        if (e1.isNull()) {
            continue;
        }

        if (e1->getType()==RS::EntityText ||
                e1->getType()==RS::EntityAttribute ||
                e1->getType()==RS::EntityAttributeDefinition) {
            continue;
        }

        QMap<REntity::Id, QSet<int> >::const_iterator it2;
        for (it2=it1; it2!=candidates.end(); it2++) {
            if (RMouseEvent::hasMouseMoved()) {
                lastSnap = RVector::invalid;
                return RVector::invalid;
            }
            QSharedPointer<REntity> e2 = document->queryEntityDirect(it2.key());
            if (e2.isNull()) {
                continue;
            }
            if (e2->getType()==RS::EntityText ||
                    e2->getType()==RS::EntityAttribute ||
                    e2->getType()==RS::EntityAttributeDefinition) {
                continue;
            }

            QList<RVector> candidates = e1->getIntersectionPoints(*e2, true, queryBox);

            if (candidates.isEmpty()) {
                continue;
            }

            RVector candidate = position.getClosest(candidates);

            dist = candidate.getDistanceTo(position);
            if (dist<minDist) {
                lastSnap = candidate;
                minDist = dist;
                entityId1 = e1->getId();
                entityId2 = e2->getId();
            }
        }
    }

    if (!lastSnap.isValid()) {
        lastSnap = position;
        lastSnap.valid = false;
        return lastSnap;
    }
    else {
        if (entityId1!=REntity::INVALID_ID) {
            entityIds.insert(entityId1);
        }
        if (entityId2!=REntity::INVALID_ID) {
            entityIds.insert(entityId2);
        }
        return lastSnap;
    }
}
Esempio n. 19
0
RVector RRestrictOrthogonal::restrictSnap(const RVector& position, const RVector& relativeZero) {
    RVector ret;
    RVector retX;
    RVector retY;

    if (documentInterface==NULL) {
        return ret;
    }

    RGraphicsView* view = documentInterface->getLastKnownViewWithFocus();
    if (view==NULL) {
        return ret;
    }

    ROrthoGrid* grid = dynamic_cast<ROrthoGrid*>(view->getGrid());
    if (grid!=NULL && grid->isIsometric()) {
        double d1, d2;
        double a1, a2;

        switch (grid->getProjection()) {
        default:
        case RS::IsoTop:
            a1 = RMath::deg2rad(30);
            a2 = RMath::deg2rad(150);
            // d1 = x / cos(30):
            d1 = (position.x - relativeZero.x) / (sqrt(3.0)/2);
            d2 = -d1;
            break;
        case RS::IsoLeft:
            a1 = RMath::deg2rad(150);
            a2 = RMath::deg2rad(90);
            d1 = (position.x - relativeZero.x) / (-sqrt(3.0)/2);
            d2 = (position.y - relativeZero.y);
            break;
        case RS::IsoRight:
            a1 = RMath::deg2rad(30);
            a2 = RMath::deg2rad(90);
            d1 = (position.x - relativeZero.x) / (sqrt(3.0)/2);
            d2 = (position.y - relativeZero.y);
            break;
        }

        retX = relativeZero + RVector::createPolar(d1, a1);
        retY = relativeZero + RVector::createPolar(d2, a2);
    }
    else {
        retX = RVector(relativeZero.x, position.y);
        retY = RVector(position.x, relativeZero.y);
    }

    switch (mode) {
    case RRestrictOrthogonal::Vertical:
        ret = retX;
        break;
    case RRestrictOrthogonal::Horizonal:
        ret = retY;
        break;
    case RRestrictOrthogonal::Orthogonal:
        if (retX.getDistanceTo(position) > retY.getDistanceTo(position)) {
            ret = retY;
        }
        else {
            ret = retX;
        }
        break;
    }

    lastSnap = ret;

    return ret;
}
Esempio n. 20
0
QList<RLine> REllipse::getTangents(const RVector& point) const {
    QList<RLine> ret;

    if (getDistanceTo(point, false) < RS::PointTolerance) {
        // point is on ellipse:
        return ret;
    }

    // point is at center (prevents recursion when swapping ellipse minor / major):
    if (point.getDistanceTo(getCenter())<RS::PointTolerance) {
        return ret;
    }

    // swap ellipse minor / major if point is on minor axis
    // 20120928: and not also on major axis (prevent recursion):
    RLine minorAxis(getCenter(), getCenter() + getMinorPoint());
    RLine majorAxis(getCenter(), getCenter() + getMajorPoint());
    if (minorAxis.isOnShape(point, false) && !majorAxis.isOnShape(point, false)) {
        REllipse e2 =*this;
        e2.majorPoint = getMinorPoint();
        e2.ratio = 1.0/ratio;
        return e2.getTangents(point);
    }

    double a = getMajorRadius();     // the length of the major axis / 2
    double b = getMinorRadius();     // the length of the minor axis / 2

    // rotate and move point:
    RVector point2 = point;
    point2.move(-getCenter());
    point2.rotate(-getAngle());

    double xp = point2.x;             // coordinates of the given point
    double yp = point2.y;

    double xt1;                      // Tangent point 1
    double yt1;
    double xt2;                      // Tangent point 2
    double yt2;

    double a2 = a * a;
    double b2 = b * b;
    double d = a2 / b2 * yp / xp;
    double e = a2 / xp;
    double af = b2 * d * d + a2;
    double bf = -b2 * d * e * 2.0;
    double cf = b2 * e * e - a2 * b2;
    double t = sqrt(bf * bf - af * cf * 4.0);
    if (RMath::isNaN(t)) {
        return ret;
    }

    yt1 = (t - bf) / (af * 2.0);
    xt1 = e - d * yt1;
    yt2 = (-t - bf) / (af * 2.0);
    xt2 = e - d * yt2;

    RVector s1(xt1, yt1);
    s1.rotate(getAngle());
    s1.move(getCenter());

    RVector s2(xt2, yt2);
    s2.rotate(getAngle());
    s2.move(getCenter());

    if (s1.isValid()) {
        ret.append(RLine(point, s1));
    }

    if (s2.isValid()) {
        ret.append(RLine(point, s2));
    }

    return ret;
}