File indexing completed on 2024-05-12 05:40:25

0001 /***************************************************************************
0002  *  Copyright (C) 2019 by Renaud Guezennec                                 *
0003  *   http://www.rolisteam.org/contact                                      *
0004  *                                                                         *
0005  *   This software is free software; you can redistribute it and/or modify *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 #include "mindmap/data/link.h"
0021 
0022 #include "mindnode.h"
0023 
0024 #include <QDebug>
0025 #include <QLineF>
0026 #include <QRectF>
0027 #include <QUuid>
0028 #include <cmath>
0029 
0030 namespace mindmap
0031 {
0032 float Link::m_minimunLenght= 150.f;
0033 Link::Link(QObject* parent) : QObject(parent), m_uuid(QUuid::createUuid().toString(QUuid::WithoutBraces))
0034 {
0035     setText(tr("is linked"));
0036 }
0037 
0038 void Link::setDirection(const mindmap::ArrowDirection& direction)
0039 {
0040     if(direction == m_dir)
0041         return;
0042     m_dir= direction;
0043     emit directionChanged();
0044 }
0045 
0046 mindmap::ArrowDirection Link::direction() const
0047 {
0048     return m_dir;
0049 }
0050 
0051 MindNode* Link::start() const
0052 {
0053     return m_start;
0054 }
0055 
0056 QString Link::p1Id() const
0057 {
0058     return m_start ? m_start->id() : QString();
0059 }
0060 
0061 QString Link::p2Id() const
0062 {
0063     return m_end ? m_end->id() : QString();
0064 }
0065 
0066 void Link::setStart(MindNode* start)
0067 {
0068     if(start == m_start)
0069         return;
0070     if(m_start)
0071         disconnect(m_start, 0, this, 0);
0072     m_start= start;
0073     emit startPointChanged();
0074 
0075     connect(m_start, &MindNode::positionChanged, this, [this]() {
0076         emit startPositionChanged();
0077         emit endPositionChanged();
0078     });
0079 }
0080 
0081 MindNode* Link::endNode() const
0082 {
0083     return m_end;
0084 }
0085 
0086 QPointF Link::endPoint() const
0087 {
0088     if(nullptr == m_end)
0089         return {};
0090     return m_end->centerPoint();
0091 }
0092 
0093 QPointF Link::startPoint() const
0094 {
0095     if(nullptr == m_start)
0096         return {};
0097     return m_start->centerPoint();
0098 }
0099 
0100 void Link::setEnd(MindNode* end)
0101 {
0102     if(end == m_end)
0103         return;
0104     if(m_end)
0105         disconnect(m_end, 0, this, 0);
0106     m_end= end;
0107     emit endPointChanged();
0108 
0109     connect(m_end, &MindNode::positionChanged, this, [this]() {
0110         emit startPositionChanged();
0111         emit endPositionChanged();
0112     });
0113 }
0114 
0115 QPointF Link::computePoint(bool p1) const
0116 {
0117     QLineF line(startPoint(), endPoint());
0118 
0119     auto node= p1 ? m_start : m_end;
0120 
0121     if(!node)
0122         return {};
0123 
0124     auto top= QLineF(node->boundingRect().topLeft(), node->boundingRect().topRight());
0125     auto bottom= QLineF(node->boundingRect().bottomLeft(), node->boundingRect().bottomRight());
0126     auto left= QLineF(node->boundingRect().topLeft(), node->boundingRect().bottomLeft());
0127     auto right= QLineF(node->boundingRect().topRight(), node->boundingRect().bottomRight());
0128 
0129     QPointF res;
0130     auto intersect= line.intersects(top, &res);
0131     if(intersect != QLineF::BoundedIntersection)
0132         intersect= line.intersects(bottom, &res);
0133 
0134     if(intersect != QLineF::BoundedIntersection)
0135         intersect= line.intersects(left, &res);
0136 
0137     if(intersect != QLineF::BoundedIntersection)
0138         line.intersects(right, &res);
0139 
0140     return res;
0141 }
0142 
0143 QPointF Link::p1() const
0144 {
0145     return computePoint(true);
0146 }
0147 
0148 QPointF Link::p2() const
0149 {
0150     return computePoint(false);
0151 }
0152 
0153 QString Link::id() const
0154 {
0155     return m_uuid;
0156 }
0157 
0158 void Link::computePosition()
0159 {
0160     auto pos1= m_start->position();
0161     pos1.setY(pos1.y() + 50);
0162     m_end->setNextPosition(pos1, this);
0163 }
0164 
0165 void Link::setText(const QString& text)
0166 {
0167     if(m_text == text)
0168         return;
0169     m_text= text;
0170     emit textChanged();
0171 }
0172 
0173 void Link::setId(const QString& text)
0174 {
0175     if(m_uuid == text)
0176         return;
0177     m_uuid= text;
0178     emit idChanged();
0179 }
0180 
0181 float Link::getStiffness() const
0182 {
0183     return m_stiffness;
0184 }
0185 
0186 void Link::setStiffness(float stiffness)
0187 {
0188     m_stiffness= stiffness;
0189 }
0190 
0191 void Link::cleanUpLink()
0192 {
0193     m_start->removeLink(this);
0194 }
0195 
0196 float Link::getLength() const
0197 {
0198     QLineF line(p1(), p2());
0199     auto r1= m_start->boundingRect();
0200     auto r2= m_end->boundingRect();
0201 
0202     auto diagonal= std::sqrt(r1.width() / 2 * r1.width() / 2 + r1.height() / 2 * r1.height() / 2)
0203                    + std::sqrt(r2.width() / 2 * r2.width() / 2 + r2.height() / 2 * r2.height() / 2) + m_minimunLenght;
0204     auto length= std::max(static_cast<float>(diagonal), std::max(static_cast<float>(line.length()), m_minimunLenght));
0205 
0206     if(m_end == nullptr || m_start == nullptr)
0207         return length;
0208 
0209     auto nodeCount= static_cast<int>(m_start->subLinks().size());
0210 
0211     auto endNodeCount= (m_end->subNodeCount() + nodeCount) / 3;
0212     auto length2= static_cast<float>(length * (1 + endNodeCount));
0213 
0214     return std::max(length, length2);
0215 }
0216 
0217 void Link::setVisible(bool vi)
0218 {
0219     if(m_visible == vi)
0220         return;
0221     m_visible= vi;
0222     emit visibleChanged();
0223 
0224     if(nullptr != m_end)
0225         m_end->setVisible(vi);
0226 }
0227 
0228 bool Link::isVisible() const
0229 {
0230     return m_visible;
0231 }
0232 
0233 QString Link::text() const
0234 {
0235     return m_text;
0236 }
0237 
0238 void Link::setMinimumLenght(float v)
0239 {
0240     m_minimunLenght= v;
0241 }
0242 
0243 QString Link::toString(bool withLabel)
0244 {
0245     return withLabel ? QStringLiteral("%1 [label=\"Link text:%2\"]").arg(m_uuid, m_text) : m_uuid;
0246 }
0247 } // namespace mindmap