RVector RSnapEntityBase::snap( const RVector& position, RGraphicsView& view, double range) { entityIds.clear(); RDocument* document = view.getDocument(); lastSnap = RVector::invalid; if (document==NULL) { lastSnap = position; lastSnap.valid = false; return lastSnap; } if (RMath::isNaN(range)) { int rangePixels = RSettings::getSnapRange(); range = view.mapDistanceFromView(rangePixels); } RBox queryBox(position, range); QSet<REntity::Id> candidates = document->queryIntersectedEntitiesXY( queryBox, true, true, RBlock::INVALID_ID); return snap(position, view, candidates, queryBox); }
RVector RSnapIntersection::snap( const RVector& position, RGraphicsView& view, double range) { entityIds.clear(); RDocument* document = view.getDocument(); if (document==NULL) { lastSnap = position; return lastSnap; } if (RMath::isNaN(range)) { int rangePixels = RSettings::getSnapRange(); range = view.mapDistanceFromView(rangePixels); } RBox queryBox(position, range); QMap<REntity::Id, QSet<int> > ids = document->queryIntersectedShapesXY( queryBox, true /*false?*/, true, RBlock::INVALID_ID, QList<RS::EntityType>() << RS::EntityHatch); return snap(position, view, ids, queryBox); }
RVector RSnapEntityBase::snap( const RVector& position, RGraphicsView& view, const QSet<REntity::Id>& candidates, const RBox& queryBox) { RDocument* document = view.getDocument(); if (document==NULL) { return lastSnap; } REntity::Id entityId; double minDist = RMAXDOUBLE; double dist; QSet<REntity::Id>::const_iterator it; for (it=candidates.begin(); it!=candidates.end(); it++) { // 20111112: query direct: //QSharedPointer<REntity> e = document->queryEntityDirect(*it); QSharedPointer<REntity> e = document->queryEntity(*it); if (e.isNull()) { continue; } RVector candidate = position.getClosest2D( snapEntity(e, position, queryBox, view) ); dist = candidate.getDistanceTo2D(position); if (dist<minDist) { lastSnap = candidate; minDist = dist; entityId = e->getId(); } } if (!lastSnap.isValid()) { lastSnap = position; lastSnap.valid = false; return lastSnap; } else { entityIds.insert(entityId); return lastSnap; } }
QList<RVector> ROrthoGrid::getIdealGridSpacing(RGraphicsView& view, int minPixelSpacing, const RVector& minSpacing, const RVector& minMetaSpacing) { RS::Unit unit = view.getDocument()->getUnit(); RS::LinearFormat linearFormat = view.getDocument()->getLinearFormat(); QList<RVector> ret; if (isFractionalFormat(linearFormat) && !RUnit::isMetric(unit)) { double idealInchSpacing = RUnit::convert(view.mapDistanceFromView(qMax(minPixelSpacing, 1)), unit, RS::Inch); RVector spacing = RUnit::convert(minSpacing, unit, RS::Inch); spacing.x = inchAutoscale(spacing.x, idealInchSpacing, unit); spacing.y = inchAutoscale(spacing.y, idealInchSpacing, unit); spacing = RUnit::convert(spacing, RS::Inch, unit); // never drop below min spacing: if (spacing.x<minSpacing.x) { spacing.x = minSpacing.x; } if (spacing.y<minSpacing.y) { spacing.y = minSpacing.y; } RVector metaSpacing = spacing; // RVector(1.0 / 64, 1.0 / 64, 1.0 / 64); metaSpacing.x = inchAutoscale(metaSpacing.x, idealInchSpacing * 4, unit); metaSpacing.y = inchAutoscale(metaSpacing.y, idealInchSpacing * 4, unit); metaSpacing = RUnit::convert(metaSpacing, RS::Inch, unit); // never drop below min spacing: if (metaSpacing.x<minMetaSpacing.x) { metaSpacing.x = minMetaSpacing.x; } if (metaSpacing.y<minMetaSpacing.y) { metaSpacing.y = minMetaSpacing.y; } // foot: never show meta grid of < 1 foot: if (unit==RS::Foot) { if (metaSpacing.x<1.0) { metaSpacing.x = 1.0; } if (metaSpacing.y<1.0) { metaSpacing.y = 1.0; } } // if (metaSpacing.x < this->metaSpacing.x) { // metaSpacing.x = this->metaSpacing.x; // } ret.append(spacing); ret.append(metaSpacing); return ret; } else { // ideal (minimum) grid spacing for the given view (some odd number): double idealSpacing = view.mapDistanceFromView(qMax(minPixelSpacing, 1)); // idealSpacing = minSpacing * idealFactor RVector idealFactor(idealSpacing / minSpacing.x, idealSpacing / minSpacing.y); // idealFactor = minSpacing * 10^n RVector n(log(idealFactor.x / minSpacing.x) / log(10.0), log(idealFactor.y / minSpacing.y) / log(10.0)); // factor = minSpacing * 10^ceil(n) RVector factor(minSpacing.x * pow(10.0, ceil(n.x - 1.0e-6)), minSpacing.y * pow(10.0, ceil(n.y - 1.0e-6))); // never drop below min spacing: if (factor.x<1.0) { factor.x = 1.0; } if (factor.y<1.0) { factor.y = 1.0; } // grid spacing: double x, y; x = minSpacing.x * factor.x; y = minSpacing.y * factor.y; ret.append(RVector(x,y)); // meta grid spacing: double mx, my; if (RMath::isNaN(minMetaSpacing.x)) { mx = x * 10; } else { //mx = minMetaSpacing.x * factor.x; mx = minMetaSpacing.x; } if (RMath::isNaN(minMetaSpacing.y)) { my = y * 10; } else { //my = minMetaSpacing.y * factor.y; my = minMetaSpacing.y; } ret.append(RVector(mx, my)); //ret.append(RVector(minSpacing.x * factor.x, minSpacing.y * factor.y)); //ret.append(RVector(minMetaSpacing.x * factor.x, minMetaSpacing.y * factor.y)); //ret.append(ret.at(0) * 10); return ret; } }
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; } }
RVector RSnapAuto::snap(const RVector& position, RGraphicsView& view, double range) { entityIds.clear(); if (RMath::isNaN(range)) { int rangePixels = RSettings::getSnapRange(); range = view.mapDistanceFromView(rangePixels); } RDocument* document = view.getDocument(); if (document==NULL) { lastSnap = position; return lastSnap; } RSnapAuto::init(); if (RMath::isNaN(range)) { int rangePixels = RSettings::getSnapRange(); range = view.mapDistanceFromView(rangePixels); } // matching ids per query range: QList<QSet<REntity::Id> > idsList; QList<RBox> queryBoxList; bool foundEntities = false; for (double r=range/1.0; r<=range+RS::PointTolerance; r+=range/1.0) { RBox queryBox(position, r); queryBoxList.append(queryBox); QMap<REntity::Id, QSet<int> > ids = document->queryIntersectedShapesXY( queryBox, true, true, RBlock::INVALID_ID // 20151027: allow snapping to hatch end points, etc: /*, QList<RS::EntityType>() << RS::EntityHatch*/); idsList.append(ids.keys().toSet()); if (ids.isEmpty()) { continue; } foundEntities = true; // intersection if (intersections) { RSnapIntersection snapIntersection; lastSnap = snapIntersection.snap(position, view, ids, queryBox); if (lastSnap.isValid() && lastSnap.getDistanceTo2d(position) < range) { status = RSnap::Intersection; entityIds = snapIntersection.getEntityIds(); return lastSnap; } } lastSnap = RVector::invalid; } // interrupted by mouse move: if (RMouseEvent::hasMouseMoved()) { status = RSnap::Free; return position; } // end points: if (foundEntities && endPoints) { for (int k=0; k<idsList.size() && k<queryBoxList.size(); k++) { // query box and matching IDs cached from intersection snap: RBox queryBox = queryBoxList.at(k); QSet<REntity::Id> ids = idsList.at(k); RSnapEnd snapEnd; lastSnap = snapEnd.snap(position, view, ids, queryBox); if (lastSnap.isValid() && lastSnap.getDistanceTo2d(position) < range) { status = RSnap::Endpoint; entityIds = snapEnd.getEntityIds(); return lastSnap; } } lastSnap = RVector::invalid; } // middle points: if (foundEntities && middlePoints) { for (int k=0; k<idsList.size() && k<queryBoxList.size(); k++) { // query box and matching IDs cached from intersection snap: RBox queryBox = queryBoxList.at(k); QSet<REntity::Id> ids = idsList.at(k); RSnapMiddle snapMiddle; lastSnap = snapMiddle.snap(position, view, ids, queryBox); if (lastSnap.isValid() && lastSnap.getDistanceTo2d(position) < range) { status = RSnap::Middle; entityIds = snapMiddle.getEntityIds(); return lastSnap; } } lastSnap = RVector::invalid; } // center points: if (foundEntities && centerPoints) { for (int k=0; k<idsList.size() && k<queryBoxList.size(); k++) { // query box and matching IDs cached from intersection snap: RBox queryBox = queryBoxList.at(k); QSet<REntity::Id> ids = idsList.at(k); RSnapCenter snapCenter; lastSnap = snapCenter.snap(position, view, ids, queryBox); if (lastSnap.isValid() && lastSnap.getDistanceTo2d(position) < range) { status = RSnap::Center; entityIds = snapCenter.getEntityIds(); return lastSnap; } } lastSnap = RVector::invalid; } // perpendicular: if (foundEntities && perpendicular) { for (int k=0; k<idsList.size() && k<queryBoxList.size(); k++) { // query box and matching IDs cached from intersection snap: RBox queryBox = queryBoxList.at(k); QSet<REntity::Id> ids = idsList.at(k); RSnapPerpendicular snapPerpendicular; lastSnap = snapPerpendicular.snap(position, view, ids, queryBox); if (lastSnap.isValid() && lastSnap.getDistanceTo2d(position) < range) { status = RSnap::Perpendicular; entityIds = snapPerpendicular.getEntityIds(); return lastSnap; } } lastSnap = RVector::invalid; } // reference points: if (foundEntities && referencePoints) { for (int k=0; k<idsList.size() && k<queryBoxList.size(); k++) { // query box and matching IDs cached from intersection snap: RBox queryBox = queryBoxList.at(k); QSet<REntity::Id> ids = idsList.at(k); RSnapReference snapReference; lastSnap = snapReference.snap(position, view, ids, queryBox); if (lastSnap.isValid() && lastSnap.getDistanceTo2d(position) < range) { status = RSnap::Reference; entityIds = snapReference.getEntityIds(); return lastSnap; } } lastSnap = RVector::invalid; } // grid points: if (gridPoints) { RSnapGrid snapGrid; lastSnap = snapGrid.snap(position, view, range); if (lastSnap.isValid() && lastSnap.getDistanceTo2d(position) < range) { status = RSnap::Grid; return lastSnap; } lastSnap = RVector::invalid; } // on entity snap is slow and almost never used: if (foundEntities && pointsOnEntity) { for (int k=0; k<idsList.size() && k<queryBoxList.size(); k++) { // query box and matching IDs cached from intersection snap: RBox queryBox = queryBoxList.at(k); QSet<REntity::Id> ids = idsList.at(k); // on entity RSnapOnEntity snapOnEntity; lastSnap = snapOnEntity.snap(position, view, ids, queryBox); if (lastSnap.isValid() && lastSnap.getDistanceTo2d(position) < range) { status = RSnap::OnEntity; entityIds = snapOnEntity.getEntityIds(); return lastSnap; } } lastSnap = RVector::invalid; } // free: if (freePositioning) { lastSnap = position; status = RSnap::Free; return lastSnap; } return RVector::invalid; }