/** * \return A presentable label for the given value. The number locale * is used to determine if the decimal point is a dot or a comma. * \see RSettings::getNumberLocale() */ QString RUnit::getLabel(double v, RDocument& document, bool forceMaxPrecision, bool forceSuppressTrailingZeroes) { if (fabs(v) < 1e-6) { v = 0.0; } return RUnit::formatLinear(v, document.getUnit(), document.getLinearFormat(), forceMaxPrecision ? 8 : document.getLinearPrecision(), false, document.showLeadingZeroes(), forceSuppressTrailingZeroes ? false : document.showTrailingZeroes()); //QLocale locale = RSettings::getNumberLocale(); //return locale.toString(v, 'g', 6); }
void RGraphicsView::autoZoom(int margin, bool ignoreEmpty) { RDocument* document = getDocument(); if (document == NULL) { return; } RBox bb = document->getBoundingBox(true, ignoreEmpty); // TODO: optional: bb.growXY( RUnit::convert( document->getMaxLineweight()/100.0/2, RS::Millimeter, document->getUnit() ) ); zoomTo(bb, (margin!=-1 ? margin : getMargin())); }
void ROrthoGrid::paintRuler(RRuler& ruler, qreal devicePixelRatio) { RDocument* doc = view.getDocument(); if (doc == NULL) { return; } RS::Unit unit = doc->getUnit(); RS::LinearFormat linearFormat = doc->getLinearFormat(); // use grid spacing if available or auto grid spacing: RVector localSpacing = spacing; if (!localSpacing.isValid() || (autoSpacing.isValid() && autoSpacing.getMagnitude2d() < localSpacing.getMagnitude2d())) { localSpacing = autoSpacing; } // use meta grid spacing if available or auto meta grid spacing: RVector localMetaSpacing = metaSpacing; if (!localMetaSpacing.isValid() || (autoMetaSpacing.isValid() && autoMetaSpacing.getMagnitude2d() < localMetaSpacing.getMagnitude2d())) { //localMetaSpacing = autoMetaSpacing; } //if (!localMetaSpacing.isValid()) { // qDebug() << "no local meta spacing"; // return; //} if (localSpacing.getMagnitude()<1.0e-6 || localMetaSpacing.getMagnitude()<1.0e-6) { //qDebug() << "local (meta) spacing too small"; return; } RVector min = gridBox.getCorner1(); RVector max = gridBox.getCorner2(); bool isHorizontal = ruler.getOrientation() == Qt::Horizontal; double tickSpacing; //if (!RUnit::isMetric(doc->getUnit())) { if (isFractionalFormat(linearFormat) && !RUnit::isMetric(unit)) { if (isHorizontal) { tickSpacing = localSpacing.x; } else { tickSpacing = localSpacing.y; } } else { if (isHorizontal) { tickSpacing = localMetaSpacing.x; } else { tickSpacing = localMetaSpacing.y; } if (view.mapDistanceToView(tickSpacing) >= 80) { tickSpacing /= 10; } else if (view.mapDistanceToView(tickSpacing) >= 30) { tickSpacing /= 5; } else if (view.mapDistanceToView(tickSpacing) >= 20) { tickSpacing /= 2; } } // ideal tick spacing in pixels: int pSpacing = (int) ceil(view.mapDistanceToView(tickSpacing)); QString l1 = RUnit::getLabel(isHorizontal ? min.x : min.y, *doc, false, true); QString l2 = RUnit::getLabel(isHorizontal ? max.x : max.y, *doc, false, true); int labelWidth = std::max( QFontMetrics(ruler.getFont()).boundingRect(l1).width(), QFontMetrics(ruler.getFont()).boundingRect(l2).width()) + 15; // smallest displayable distance between labels in steps (ticks): int minLabelStep = 1; if (pSpacing>0) { minLabelStep = labelWidth / pSpacing + 1; } int labelStep = minLabelStep; //if (!RUnit::isMetric(doc->getUnit())) { if (isFractionalFormat(linearFormat) && !RUnit::isMetric(unit)) { // non metric double f = 1.0/128; do { if (localMetaSpacing.isValid()) { if (isHorizontal) { labelStep = RMath::mround(localMetaSpacing.x / localSpacing.x) * f; } else { labelStep = RMath::mround(localMetaSpacing.y / localSpacing.y) * f; } } else { labelStep = (int)f; } f = f * 2; if (f>65536) { labelStep = -1; } } while (labelStep < minLabelStep && labelStep>=0); } else { // metric if (labelStep >= 3 && labelStep <= 4) { labelStep = 5; } else if (labelStep >= 6 && labelStep <= 9) { labelStep = 10; } else if (labelStep >= 11 && labelStep <= 19) { labelStep = 20; } else if (labelStep >= 21 && labelStep <= 99) { labelStep = 100; } } if (labelStep<0) { return; } if (labelStep<1) { labelStep = 1; } double minPos; double maxPos; if (isHorizontal) { minPos = (floor(view.mapFromView(RVector(0, 0)).x / (labelStep * tickSpacing))-1) * (labelStep * tickSpacing); maxPos = (ceil(view.mapFromView(RVector(view.getWidth(), 0)).x / (labelStep * tickSpacing))+1) * (labelStep * tickSpacing); } else { minPos = (floor(view.mapFromView(RVector(0, view.getHeight())).y / (labelStep * tickSpacing))-1) * (labelStep * tickSpacing); maxPos = (ceil(view.mapFromView(RVector(0, 0)).y / (labelStep * tickSpacing))+1) * (labelStep * tickSpacing); } if ((maxPos - minPos) / tickSpacing > 1e3) { return; } int c; double p; for (c = 0, p = minPos; p < maxPos; p += tickSpacing, ++c) { bool hasLabel = c % labelStep == 0; double v; if (isHorizontal) { v = view.mapToView(RVector(p, 0)).x; } else { v = view.mapToView(RVector(0, p)).y; } ruler.paintTick(v*devicePixelRatio, hasLabel, hasLabel ? RUnit::getLabel(p, *doc, false, true, true) : QString()); } }
/** * Updates the grid information, in particular the grid spacing and * grid region to the current view port. */ void ROrthoGrid::update(bool force) { if (!force && viewBox==view.getBox()) { return; } viewBox = view.getBox(); int viewportNumber = view.getViewportNumber(); RDocument* doc = view.getDocument(); if (doc == NULL) { qWarning() << "ROrthoGrid::update: document is NULL"; return; } RGraphicsScene* scene = view.getScene(); if (scene==NULL) { qWarning() << "ROrthoGrid::update: scene is NULL"; return; } RS::ProjectionRenderingHint hint = scene->getProjectionRenderingHint(); // for 3d views, we have no convenient way to calculate the grid dimensions: if (hint == RS::RenderThreeD) { gridBox = RBox(RVector(-1000, -1000), RVector(1000, 1000)); spacing = RVector(10.0, 10.0); return; } QString key; key = QString("Grid/IsometricGrid0%1").arg(viewportNumber); isometric = doc->getVariable(key, false, true).toBool(); RS::Unit unit = doc->getUnit(); RS::LinearFormat linearFormat = doc->getLinearFormat(); // default values for missing configurations and 'auto' settings: minSpacing.valid = true; minMetaSpacing.valid = true; if (isFractionalFormat(linearFormat) && !RUnit::isMetric(unit)) { //minSpacing.x = minSpacing.y = RNANDOUBLE; //minMetaSpacing.x = minMetaSpacing.y = RNANDOUBLE; minSpacing.x = minSpacing.y = RUnit::convert(1.0, RS::Inch, unit) / 1024; minMetaSpacing.x = minMetaSpacing.y = RUnit::convert(1.0, RS::Inch, unit) / 1024; } else { minSpacing.x = minSpacing.y = 1.0e-6; minMetaSpacing.x = minMetaSpacing.y = RNANDOUBLE; //minSpacing.x = minSpacing.y = RNANDOUBLE; //minMetaSpacing.x = minMetaSpacing.y = 1.0e-6; } key = QString("Grid/GridSpacingX0%1").arg(viewportNumber); QVariant strSx = doc->getVariable(key, QVariant(), true); key = QString("Grid/GridSpacingY0%1").arg(viewportNumber); QVariant strSy = doc->getVariable(key, QVariant(), true); spacing.valid = true; bool autoX = !strSx.isValid() || strSx.toString()=="auto"; bool autoY = !strSy.isValid() || strSy.toString()=="auto"; // grid spacing x: if (!autoX) { // fixed: double d = RMath::eval(strSx.toString()); if (!RMath::hasError() && d>RS::PointTolerance) { minSpacing.x = spacing.x = d; } } // grid spacing y: if (!autoY) { double d = RMath::eval(strSy.toString()); if (!RMath::hasError() && d>RS::PointTolerance) { minSpacing.y = spacing.y = d; } } // meta grid: key = QString("Grid/MetaGridSpacingX0%1").arg(viewportNumber); QVariant strMsx = doc->getVariable(key, QVariant(), true); key = QString("Grid/MetaGridSpacingY0%1").arg(viewportNumber); QVariant strMsy = doc->getVariable(key, QVariant(), true); metaSpacing.valid = true; bool metaAutoX = !strMsx.isValid() || strMsx.toString()=="auto"; bool metaAutoY = !strMsy.isValid() || strMsy.toString()=="auto"; // meta grid spacing x: if (!metaAutoX) { // fixed: double d = RMath::eval(strMsx.toString()); if (d>RS::PointTolerance) { minMetaSpacing.x = metaSpacing.x = d; } } // meta grid spacing y: if (!metaAutoY) { // fixed: double d = RMath::eval(strMsy.toString()); if (d>RS::PointTolerance) { minMetaSpacing.y = metaSpacing.y = d; } } // auto scale grid: QList<RVector> s = getIdealSpacing(minPixelSpacing, minSpacing, minMetaSpacing); if (RSettings::getAutoScaleGrid()) { autoSpacing = spacing = s.at(0); } if (RSettings::getAutoScaleMetaGrid()) { autoMetaSpacing = metaSpacing = s.at(1); } // switch grid off below given pixel limit: if (view.mapDistanceToView(spacing.x) < minPixelSpacing) { spacing = RVector::invalid; } if (view.mapDistanceToView(metaSpacing.x) < minPixelSpacing) { metaSpacing = RVector::invalid; } if (view.mapDistanceToView(spacing.y) < minPixelSpacing) { spacing = RVector::invalid; } if (view.mapDistanceToView(metaSpacing.y) < minPixelSpacing) { metaSpacing = RVector::invalid; } // qDebug() << "spacing: " << spacing; // qDebug() << "minSpacing: " << minSpacing; // qDebug() << "metaSpacing: " << metaSpacing; // if (scaleGrid) { // QList<RVector> s = ROrthoGrid::getIdealSpacing(view, minPixelSpacing, minSpacing); // spacing = s.at(0); // metaSpacing = s.at(1); // } else { // spacing = minSpacing; // } RVector minGridPoint; RVector maxGridPoint; spacing.z = 1; if (isometric) { spacing.x = spacing.y * 2.0 * sin(M_PI/3.0); metaSpacing.x = metaSpacing.y * 2.0 * sin(M_PI/3.0); spacing = spacing / 2; //metaSpacing = metaSpacing / 2; } minGridPoint = viewBox.getCorner1(); minGridPoint = minGridPoint.getDividedComponents(spacing).getFloor(); minGridPoint = minGridPoint.getMultipliedComponents(spacing); maxGridPoint = viewBox.getCorner2(); maxGridPoint = maxGridPoint.getDividedComponents(spacing).getCeil(); maxGridPoint = maxGridPoint.getMultipliedComponents(spacing); minGridPoint.z = viewBox.getCorner1().z; maxGridPoint.z = viewBox.getCorner2().z; gridBox = RBox(minGridPoint, maxGridPoint); minGridPoint = viewBox.getCorner1(); minGridPoint = minGridPoint.getDividedComponents(metaSpacing).getFloor(); minGridPoint = minGridPoint.getMultipliedComponents(metaSpacing); maxGridPoint = viewBox.getCorner2(); maxGridPoint = maxGridPoint.getDividedComponents(metaSpacing).getCeil(); maxGridPoint = maxGridPoint.getMultipliedComponents(metaSpacing); minGridPoint.z = viewBox.getCorner1().z; maxGridPoint.z = viewBox.getCorner2().z; metaGridBox = RBox(minGridPoint, maxGridPoint); if (isometric) { QString i1 = RUnit::getLabel(spacing.x / cos(M_PI/6), *doc, true, true); QString i2 = RUnit::getLabel(metaSpacing.x / cos(M_PI/6) / 2, *doc, true, true); infoText = QString("%1 < %2").arg(i1).arg(i2); } else { QString i1 = RUnit::getLabel(spacing.x, *doc, true, true); QString i2 = RUnit::getLabel(metaSpacing.x, *doc, true, true); infoText = QString("%1 < %2").arg(i1).arg(i2); } }
void RClipboardOperation::copy( RDocument& src, RDocument& dest, const RVector& offset, double scale, double rotation, bool flipHorizontal, bool flipVertical, bool toCurrentLayer, bool toCurrentBlock, bool overwriteLayers, bool overwriteBlocks, const QString& blockName, const QString& layerName, RTransaction& transaction, bool selectionOnly, bool clear, bool toModelSpaceBlock, bool preview, const RQMapQStringQString& attributes) const { bool overwriteLinetypes = false; double unitScale; if (src.getUnit()==RS::None) { unitScale = 1.0; } else { unitScale = RUnit::convert(1.0, src.getUnit(), dest.getUnit()); } if (clear) { dest.clear(); } QSet<REntity::Id> entityIdsSet; if (selectionOnly) { entityIdsSet = src.querySelectedEntities(); } else { entityIdsSet = src.queryAllEntities(); } QList<REntity::Id> entityIdsList = src.getStorage().orderBackToFront(entityIdsSet); // Non-const offset. reset to 0/0/0 if copying to block // (offset implemented as block reference offset). RVector off = offset; bool hasBlock = false; QSet<REntity::Id> attributeIds; // this part is used to insert ('paste') blocks from the part library // as new blocks: QSharedPointer<RBlockReferenceEntity> refp; if (!blockName.isNull()) { QSharedPointer<RBlock> block; hasBlock = dest.hasBlock(blockName); // block does not exist in dest - or - // block exists in dest and must be overwritten: if (!hasBlock || overwriteBlocks) { block = QSharedPointer<RBlock> (new RBlock(&dest, blockName, RVector(0, 0, 0))); transaction.overwriteBlock(block); } // block exists and must not be overwritten: else { block = dest.queryBlock(blockName); } Q_ASSERT(!block.isNull()); // create new block reference that references new, overwritten or existing block // (insert later, when block is complete, so we have bounding box for spatial index): RBlockReferenceEntity* ref = new RBlockReferenceEntity(&dest, RBlockReferenceData(block->getId(), RVector(0,0,0), RVector(1.0, 1.0, 1.0), 0.0)); refp = QSharedPointer<RBlockReferenceEntity>(ref); refp->setBlockId(dest.getCurrentBlockId()); off = RVector(0, 0, 0); if (flipHorizontal) { refp->flipHorizontal(); } if (flipVertical) { refp->flipVertical(); } //ref->scale(scale * unitScale); refp->scale(scale); refp->rotate(rotation); refp->move(offset); // create attribute for each attribute definition in block with // invalid parent ID (fixed later, when block reference ID is known): QSet<REntity::Id> ids = src.queryAllEntities(); QSet<REntity::Id>::iterator it; for (it=ids.begin(); it!=ids.end(); it++) { REntity::Id id = *it; QSharedPointer<RAttributeDefinitionEntity> attDef = src.queryEntity(id).dynamicCast<RAttributeDefinitionEntity>(); if (attDef.isNull()) { continue; } QSharedPointer<RAttributeEntity> att( new RAttributeEntity( &dest, RAttributeData(attDef->getData(), REntity::INVALID_ID, attDef->getTag()) ) ); att->scale(unitScale); refp->applyTransformationTo(*att); // assign values to attributes: QString tag = att->getTag(); if (attributes.contains(tag)) { att->setText(attributes[tag]); } // make sure the attribute has the correct layer ID of the // corresponding layer in dest: QSharedPointer<RLayer> destLayer = copyEntityLayer(*attDef, src, dest, overwriteLayers, transaction); att->setLayerId(destLayer->getId()); QSharedPointer<RLinetype> destLinetype = copyEntityLinetype(*attDef, src, dest, overwriteLinetypes, transaction); att->setLinetypeId(destLinetype->getId()); transaction.addObject(att, false); attributeIds.insert(att->getId()); } scale = 1.0; rotation = 0.0; flipHorizontal = false; flipVertical = false; toCurrentLayer = false; //toCurrentBlock = false; } // copy entities from src to dest: // if the block existed already in dest and is not overwritten, // there's nothing to do here: if (!hasBlock || overwriteBlocks || preview) { copiedLayers.clear(); copiedLinetypes.clear(); copiedBlocks.clear(); int counter = 0; QList<REntity::Id>::iterator it; for (it=entityIdsList.begin(); it!=entityIdsList.end(); ++it) { if (preview && ++counter>RSettings::getPreviewEntities()) { break; } QSharedPointer<REntity> entity = src.queryEntityDirect(*it); if (entity.isNull() || entity->isUndone()) { continue; } copyEntity( *entity.data(), src, dest, off, scale, unitScale, rotation, flipHorizontal, flipVertical, toCurrentLayer, toCurrentBlock, overwriteLayers, overwriteBlocks, blockName, transaction, toModelSpaceBlock // to model space: true for copy // (allow copy from inside any block definition), // false for paste ); } } // only overwrite layers: else if (overwriteLayers) { copiedLayers.clear(); int counter = 0; QList<REntity::Id>::iterator it; for (it=entityIdsList.begin(); it!=entityIdsList.end(); ++it) { if (preview && ++counter>RSettings::getPreviewEntities()) { break; } QSharedPointer<REntity> entity = src.queryEntityDirect(*it); if (entity.isNull() || entity->isUndone()) { continue; } copyEntityLayer( *entity.data(), src, dest, overwriteLayers, transaction ); } } // copying of entire block complete, insert block reference now since // we now have the bounding box for the spatial index: if (!refp.isNull()) { bool useCurrentAttributes = true; if (!layerName.isEmpty()) { useCurrentAttributes = false; refp->setLayerId(dest.getLayerId(layerName)); } transaction.addObject(refp, useCurrentAttributes); // fix parent ID of attributes created by the new inserted block: REntity::Id refId = refp->getId(); //QSet<REntity::Id> ids = dest.queryAllEntities(); QSet<REntity::Id>::iterator it; for (it=attributeIds.begin(); it!=attributeIds.end(); it++) { REntity::Id id = *it; QSharedPointer<RAttributeEntity> e = dest.queryEntityDirect(id).dynamicCast<RAttributeEntity>(); if (e.isNull()) { continue; } if (e->getParentId()==REntity::INVALID_ID) { e->setParentId(refId); } } } transaction.endCycle(); }
/** * Adds the given entity (and its layer(s) and block reference(s)) to the * given document. * * \param blockName Name of an existing block in dest */ void RClipboardOperation::copyEntity( REntity& entity, RDocument& src, RDocument& dest, const RVector& offset, double scale, double unitScale, double rotation, bool flipHorizontal, bool flipVertical, bool toCurrentLayer, bool toCurrentBlock, bool overwriteLayers, bool overwriteBlocks, const QString& blockName, RTransaction& transaction, bool toModelSpaceBlock) const { bool overwriteLinetypes = false; QSharedPointer<RLayer> destLayer = copyEntityLayer(entity, src, dest, overwriteLayers, transaction); QSharedPointer<RLinetype> destLinetype = copyEntityLinetype(entity, src, dest, overwriteLinetypes, transaction); // add block the entity belongs to, if the block exists it is overwritten // if 'overwriteBlocks' is true: QSharedPointer<RBlock> srcBlock = src.queryBlock(entity.getBlockId()); if (srcBlock.isNull()) { qWarning("RClipboardOperation::copyToDocument: " "block of entity is NULL."); return; } QString srcBlockName = srcBlock->getName(); QSharedPointer<RBlock> destBlock; if (copiedBlocks.contains(srcBlockName)) { destBlock = copiedBlocks.value(srcBlockName); } else { QString destBlockName; if (!blockName.isNull()) { destBlockName = blockName; } else { if (toCurrentBlock) { destBlockName = dest.getBlockName(dest.getCurrentBlockId()); } else { destBlockName = srcBlock->getName(); } } if (!dest.hasBlock(destBlockName) || (overwriteBlocks && blockName.isNull())) { destBlock = QSharedPointer<RBlock> (srcBlock->clone()); dest.getStorage().setObjectId(*destBlock.data(), RObject::INVALID_ID); dest.getStorage().setObjectHandle(*destBlock.data(), RObject::INVALID_HANDLE); destBlock->setDocument(&dest); if (dest.hasBlock(destBlockName)) { if (!transaction.overwriteBlock(destBlock)) { destBlock = dest.queryBlock(destBlockName); } } else { transaction.addObject(destBlock); } } else { destBlock = dest.queryBlock(destBlockName); } copiedBlocks.insert(srcBlockName, destBlock); } Q_ASSERT(destBlock->getId()!=RBlock::INVALID_ID); // entity is a block reference: // add entities of the block the block reference refers to (the block // definition is then added automatically): // if block contents has already been copied, do nothing RBlockReferenceEntity* blockRef = dynamic_cast<RBlockReferenceEntity*>(&entity); if (blockRef!=NULL && !copiedBlockContents.contains(blockRef->getReferencedBlockId())) { QSharedPointer<RBlock> refBlock = src.queryBlock(blockRef->getReferencedBlockId()); if (refBlock.isNull()) { qWarning("RClipboardOperation::copyToDocument: " "entity references a NULL block."); return; } copiedBlockContents.insert(blockRef->getReferencedBlockId()); // TODO: don't do this twice: //qDebug() << "RClipboardOperation::copyToDocument: copying block: " << refBlock->getName(); // if block exists in dest, it has already been copied or was // already there and needs to be overwritten: QSharedPointer<RBlock> refBlockDest = dest.queryBlock(refBlock->getName()); if (refBlockDest.isNull() || overwriteBlocks) { QSet<REntity::Id> ids = src.queryBlockEntities(refBlock->getId()); bool first = true; QSet<REntity::Id>::iterator it; for (it=ids.begin(); it!=ids.end(); ++it) { QSharedPointer<REntity> e = src.queryEntityDirect(*it); if (e.isNull()) { continue; } copyEntity( *e.data(), src, dest, RVector::nullVector, 1.0, // scale from user options not applied to block contents // but to block reference unitScale, 0.0, false, false, // no flips false, false, // keep original block and layer overwriteLayers, first && overwriteBlocks, QString(), transaction, false // not to model space but actual block ); first = false; } } } // add entity self: QSharedPointer<REntity> destEntity = QSharedPointer<REntity>(entity.clone()); //dest.getStorage().setObjectId(*destEntity.data(), RObject::INVALID_ID); dest.getStorage().setObjectHandle(*destEntity.data(), RObject::INVALID_HANDLE); destEntity->setSelected(false); // apply transformations: if (flipHorizontal) { destEntity->flipHorizontal(); } if (flipVertical) { destEntity->flipVertical(); } if (blockRef!=NULL) { destEntity->scale(scale); } else { destEntity->scale(scale * unitScale); } destEntity->rotate(rotation); // correct block reference offset. necessary for unit conversion: if (blockRef!=NULL && src.getUnit()!=dest.getUnit()) { destEntity->move(-blockRef->getPosition()); destEntity->move(blockRef->getPosition() * unitScale); } destEntity->move(offset); destEntity->setDocument(&dest); if (toCurrentLayer) { // paste to current layer: destEntity->setLayerId(dest.getCurrentLayerId()); } else { // paste to original layer: Q_ASSERT(!destLayer.isNull()); destEntity->setLayerId(destLayer->getId()); } destEntity->setLinetypeId(destLinetype->getId()); if (toModelSpaceBlock) { destEntity->setBlockId(dest.getModelSpaceBlockId()); } else { destEntity->setBlockId(destBlock->getId()); } // correct referenced block id of pasted block reference: QSharedPointer<RBlockReferenceEntity> destBlockRef = destEntity.dynamicCast<RBlockReferenceEntity>(); if (!destBlockRef.isNull() && blockRef!=NULL) { QString bn = src.getBlockName(blockRef->getReferencedBlockId()); RBlock::Id blockId = dest.getBlockId(bn); destBlockRef->setReferencedBlockId(blockId); // qDebug() << "not yet updated block ref: " << *destBlockRef; // destBlockRef->update(); // qDebug() << "updated block ref: " << *destBlockRef; } transaction.addObject(destEntity, false, true); }