Scale all elements in model by 25.4

I'm using Microstation Connect Update 10 and I'm trying to modify a dgn file(not the active file) and then save it as a dwg file for our cnc operations. Part of the modifications include dropping all the cells and complex elements to geometry, deleting some object and modifying others (rotate, move, etc...), and finally scaling up the entire drawing by 25.4 as it needs to be metric for this particular machine to read. I'm attaching the code I have so far which works perfectly for the active file if I change the model ref. It also works perfectly for converting an unopened dgn file to a dwg.... accept for the scaling that takes place at the end. When I run this it does everything it is supposed to, but when I include the scaling portion it makes a complete mess of the active drawing even though I don't have it referenced anywhere in code. 

Any Help Appreciated

Thanks

Dave

void SaveAsDwg (WCharCP unparsed)
{
	/* create a pointer and point at nothing */
	DgnFilePtr dgnfileStnHr = nullptr;

	/* original file path and name */
	WString fileName(LR"(C:\Users\drodenhizer\Documents\2022-172 TSCP-1.dgn)");

	/* document pointer to above file */
	DgnDocumentPtr dgndocStnhrSeed = DgnDocument::CreateForLocalFile(fileName.c_str());
	
	/* create a set to store levels to be modified */
	set<UInt32> intLstLvls{ };
	
	MSElementDescr* eledscr = 0;
	
	UInt32 filePos = 0;
	
	/* check to see if pointer is valid	*/
	if (dgndocStnhrSeed.IsValid())
	{
		// create an in memory representation of original file
		dgnfileStnHr = DgnFile::Create(*dgndocStnhrSeed, DgnFileOpenMode::ReadWrite);

		// check file validity
		if (dgnfileStnHr.IsValid())
		{	
			// needed for dgndocument return values
		   	StatusInt *stsLoad = new StatusInt();
			DgnFileStatus newfile = DgnFileStatus();
			
			// load file
			dgnfileStnHr->LoadDgnFile(stsLoad);

			// complete name for new file
			WString fileNameNew(LR"(C:\Users\drode\Documents\2022-XXX TSCP-1.dwg)");

			// location for new file
			WString filePathNew(LR"(C:\Users\drode\Documents\)");

			// create a new document pointer for the save as function to overwrite
			DgnDocumentPtr dgndocStnhr = DgnDocument::CreateForNewFile(newfile, fileNameNew.c_str(),
				NULL, (int)DgnFileFormatType::Current, filePathNew.c_str(), DgnDocument::OverwriteMode::Always, DgnDocument::CreateOptions::Default);

			// save original file under new file name. note: even though this is the new file, manipulations are still preformed on the original
			dgnfileStnHr->DoSaveAs(*dgndocStnhr, DgnFileFormatType::DWG, true, false);
			
			Int32 mdlId = dgnfileStnHr->GetDefaultModelId();

			DgnModelP model = dgnfileStnHr->FindLoadedModelById(mdlId);			
			
			Int32 eleCnt = model->GetElementCount(DgnModelSections::All);
			WPrintfString myStr(L"");
			myStr.Sprintf(L"ele Count = %zu,", eleCnt);
			mdlDialog_dmsgsPrint(myStr.GetWCharCP());
	
			dgnfileStnHr->FillSectionsInModel(model, DgnModelSections::All);

			GetLevelIds(intLstLvls, *model);
				
				/* loop through all elements drop all cells to geometry	*/
				for (EditElementHandle eehSteinElms : model->GetElementsCollection())
				{
					// ================ this works ========================================================↓
					if (CELL_HEADER_ELM == eehSteinElms.GetElementType())
					{		
						DisplayHandlerP handler = eehSteinElms.GetDisplayHandler();
					
						if (nullptr != handler)
						{
							NormalCellHeaderHandler* cellHandler = dynamic_cast<NormalCellHeaderHandler*>(handler);
							if (nullptr != cellHandler)
							{
								DropGeometryPtr dropGeometry = DropGeometry::Create();
								dropGeometry->SetOptions(DropGeometry::OPTION_Complex);
								ElementAgenda agenda;
					
								WChar name[MAX_MODEL_NAME_LENGTH];
								cellHandler->ExtractName(name, MAX_MODEL_NAME_LENGTH, eehSteinElms);
								cellHandler->Drop(eehSteinElms, agenda, *dropGeometry);
								
								for (EditElementHandleR eehR : agenda)
								{
									eehR.AddToModel();
								}
							}
						}
						eehSteinElms.DeleteFromModel();
					}
				}
			
				/* loops through all elements and scales up by 25.4	*/
				for (EditElementHandle ehForScl : model->GetElementsCollection())
				{
					if (SUCCESS == mdlAssoc_getElementDescr(&eledscr, &filePos, ehForScl.GetElementId(),ehForScl.GetModelRef() , FALSE))
					{
						Transform tMatrix;
						mdlTMatrix_getIdentity(&tMatrix);
						Transform sMatrix;
						mdlTMatrix_getIdentity(&sMatrix);
						mdlTMatrix_scale(&sMatrix, &sMatrix, 25.4, 25.4, 25.4);
						mdlElmdscr_transformAllowModification(&eledscr, &tMatrix, ehForScl.GetModelRef(), ehForScl.GetModelRef(), 0);
						mdlElmdscr_transform(&eledscr, &sMatrix);
						mdlElmdscr_rewrite(eledscr, eledscr, filePos);
						mdlElmdscr_freeAll(&eledscr);
					}
				}

			dgnfileStnHr->ProcessChanges(DgnSaveReason::FileSaveAs);
		}
	}
}

  • Hi,

    it looks like there is nobody with any great idea ;-)

    I'm using Microstation Connect Update 10

    Oops, it is very old MicroStation version (4 years old), where I would expect some bugs in API.

    and finally scaling up the entire drawing by 25.4

    Isn't it easier to scale everything in the first step (so the cell are scaled as the whole, including content)?

    by 25.4 as it needs to be metric for this particular machine to read.

    I do not know the context (and you share no example), but it sounds weird: DGN file is "units agnostic", so to switch from inches to meters is only about to change working (master) units, nothing else. Because elements are stored in UORs, MicroStation only change the scale ratio between UORs and the used units, so elements maintain the size, but are represented in meters.

    I'm attaching the code I have so far which works perfectly for the active file if I change the model ref.

    I am not sure I understand what you mean by "if I change the model ref"?

    What is the structure of the converted files? From the description above it looks like there is separate DGN file (with no references).

    I'm attaching the code

    Why transformation (scaling) is done using this so old C-style code, when ApplyTransform method is available? It looks weird when you use C++ API to obtain EditElementHandles from ElementsCollection and you jump down to old C to transform the descriptor.

    but when I include the scaling portion it makes a complete mess of the active drawing

    What type of "mess" you mean? Why did you not share any picture or the result data to demonstrate the problem?

    Regards,

      Jan

  • Oops, it is very old MicroStation version (4 years old), where I would expect some bugs in API.

    I was mistaken. I'm actually using Promis.e Connect Update 10, which is the most recent version, not sure how that relates to Microstation Core.

    Isn't it easier to scale everything in the first step (so the cell are scaled as the whole, including content)?

    You are correct. That is how I ended up proceeding.

    As far as the scale. The CNC machine that is reading the final dwg is metric so it needs to see 1 as an inch in dgn as 25.4 in dwg. I know there is probably a different/better way to accomplish this, but this is the way we've been doing it manually...for better or worse;-) 

    I am not sure I understand what you mean by "if I change the model ref"?

    I just meant that if I run this code using the Active Model as my modelref it works.

    Why transformation (scaling) is done using this so old C-style code,

    Yes..I stumbled upon this last weekend. I've only been learning c++ for a couple months so all this is completely new. 

    							Transform transform;
    							mdlTMatrix_getIdentity(&transform);
    							mdlTMatrix_scale(&transform, &transform, 25.4, 25.4, 25.4);
    							TransformInfo tinfo(transform);
    							eleHand.GetHandler().ApplyTransform(eleHand, tinfo);
    							eleHand.ReplaceInModel(eleHand.GetElementRef());
    

    I ended up getting it to work with the above code.

    What type of "mess" you

    Like I said. I'm new to c++ programming, but I think it had something to do with either the file position or the descr references...by 'mess' I meant everything on the drawing lines, arcs, text, etc, was scrambled, deleted, partially deleted, moved , skewed...basically like a bomb went off in the middle of the drawing.

    Thanks for your reply.

    Do you know how I'd go about getting the x,y or z rotation of an arc? That is what I having trouble with now. I'm going to start a new post on this, but just curious if you have any insight.

    Thanks again

    Dave

  • which is the most recent version, not sure how that relates to Microstation Core.

    I am not sure if key-in "version" can be used (if it reports Platform version), but for sure you can check the version of ustation.dll (in file properties), which is set to the platform version (not the product itself).

    The CNC machine that is reading the final dwg is metric so it needs to see 1 as an inch in dgn as 25.4 in dwg.

    Hmmm ... I would assume it should be done during the conversion. But I am metric guy, so imperial units look like something between chaos and magic, so when it works (and can be processed in AutoCAD, where units is another nightmare), that's fine :-)

    I ended up getting it to work with the above code.

    Still too complicated (and there is no reason to use mdlTMatrix_ at all).

    I think something similar to this code (not tested, it's long time I wrote pure C++ code ;-) should be enough and clearer:

    DPoint3d origin = DPoint3d::FromZero();
    Transform transform = Transform::FromFixedPointAndScaleFactors(origin, 25.4, 25.4, 25.4);
    TransformInfo tinfo(transform);
    ...

    Do you know how I'd go about getting the x,y or z rotation of an arc?

    Please ask in a new post! And before that, check DEllipse3d class and maybe also ICurvePathQuery.

    With regards,

      Jan

  • Thanks for your help. I'll check into these and create a new post.

    Dave