Bug of ON_Brep::Tranform() or CRhinoDoc::ReplaceObject() ? c++

Hi;

    CRhinoGetObject go;
	go.SetCommandPrompt(L"Select Breps");
	go.EnableReferenceObjectSelect(false);
	go.EnableSubObjectSelect(false);
	go.EnableGroupSelect(true);
	go.SetGeometryFilter(ON::brep_object);
	go.GetObjects(1, 0);
	if (go.CommandResult() != CRhinoCommand::success)
		return go.CommandResult();
	ON_3dVector ve_move(5.0, 5.0, 0.0);
	ON_Xform xf_move = ON_Xform::TranslationTransformation(ve_move);
	ON_Xform xf_sc = ON_Xform::ScaleTransformation(ON_Plane::World_xy, 3.0, 3.0, 1.0);
	ON_SimpleArray<CRhinoObject*> ObjectList;
	for (int i = 0; i < go.ObjectCount(); i++)
	{
		ON_Brep* br = go.Object(i).Brep()->Duplicate();
		br->Transform(xf_move);
		ObjectList.Append(RhinoApp().ActiveDoc()->AddBrepObject(*br));
	}
	for (int i = 0; i < go.ObjectCount(); i++)
	{
		ON_Brep* br = go.Object(i).Brep()->Duplicate();
		br->Transform(xf_move * xf_sc);                // seems to be failing to Scale
		RhinoApp().ActiveDoc()->ReplaceObject(ObjectList[i], *br);
	}

The_file.3dm (61.0 KB)
My code seems to be failing to Scale objects, I kown RhinoApp().ActiveDoc()->TransformObject() can be transform good, but it can not use in History.
What I want to know is is there a good way to implement my own transform function ?

Hi @suc_kiet,

Maybe this?

CRhinoCommand::result CCommandTest::RunCommand(const CRhinoCommandContext& context)
{
  CRhinoGetObject go;
  go.SetCommandPrompt(L"Select Breps");
  go.EnableReferenceObjectSelect(false);
  go.EnableSubObjectSelect(false);
  go.EnableGroupSelect(true);
  go.SetGeometryFilter(ON::brep_object);
  go.GetObjects(1, 0);
  if (go.CommandResult() != CRhinoCommand::success)
    return go.CommandResult();

  ON_3dVector dir(5.0, 5.0, 0.0);
  ON_Xform xf_move = ON_Xform::TranslationTransformation(dir);
  ON_Xform xf_scale = ON_Xform::ScaleTransformation(ON_Plane::World_xy, 3.0, 3.0, 1.0);
  ON_Xform xf_final = xf_move * xf_scale;

  for (int i = 0; i < go.ObjectCount(); i++)
  {
    const CRhinoObject* obj = go.Object(i).Object();
    if (obj)
      context.m_doc.TransformObject(obj, xf_final, true, true, true);
  }
  context.m_doc.Redraw();

  return CRhinoCommand::success;
}

Hi @dale,
Sorry, I didn’t describe it clearly, I’m uploading the code again now.

class CCommandTest : public CRhinoScriptCommand
{
public:
	CCommandTest() = default;
	UUID CommandUUID() override
	{
		// {C1BEC3E3-4DAA-45AC-A02D-9F1FD3944D36}
		static const GUID TestCommand_UUID =
		{ 0xC1BEC3E3, 0x4DAA, 0x45AC, { 0xA0, 0x2D, 0x9F, 0x1F, 0xD3, 0x94, 0x4D, 0x36 } };
		return TestCommand_UUID;
	}
	const wchar_t* EnglishCommandName() override { return L"TransformHistory_Test"; }
	CRhinoCommand::result RunCommand(const CRhinoCommandContext& context) override;

	CRhinoObject* ReplayHistory(const class CRhinoHistoryRecord& history_record);
	bool WriteHistory(
		CRhinoHistory& history,
		CRhinoObjRef obj0,
		ON_Xform mxf);

	bool ReadHistory(
		const CRhinoHistoryRecord& history_record,
		CRhinoObjRef& obj0,
		ON_Xform& mxf);

	static const int m_sample_history_version;
};

static class CCommandTest TestCommand;

const int CCommandTest::m_sample_history_version(20220122);
bool CCommandTest::WriteHistory(
	CRhinoHistory& history,
	CRhinoObjRef Crv0,
	ON_Xform mxf)
{
	if (!history.SetObjRefValue(0, Crv0))
		return false;
	if (!history.SetXformValue(1, mxf))
		return false;
	history.SetHistoryVersion(m_sample_history_version);

	return true;
}

bool CCommandTest::ReadHistory(
	const CRhinoHistoryRecord& history_record,
	CRhinoObjRef& Crv0,
	ON_Xform& mxf)
{
	// Check to make sure this history record was made with this version
	if (m_sample_history_version != history_record.HistoryVersion())
		return false;
	if (!history_record.GetRhinoObjRef(0, Crv0))
		return false;
	if (!history_record.m_hr.GetXformValue(1, mxf))
		return false;
	return true;
}

CRhinoObject* CCommandTest::ReplayHistory(const class CRhinoHistoryRecord& history_record)
{
	CRhinoObjRef Crv0;
	ON_Xform mxf;
	if (ReadHistory(history_record, Crv0, mxf))
	{
		if (Crv0.Object() != nullptr)
		{
			//xf_Global = mxf;      //In my Plugin, I must get the history transformation in this position
			CRhinoObject* result = nullptr;
			CRhinoDoc* doc = Crv0.Object()->Document();
			if (0 == doc)
			{
				return result;
			}
			result = doc->TransformObject(Crv0, mxf, false, false, false);// This position will cause rhino to crash
			return result;
		}
	}
	return 0;
}

CRhinoCommand::result CCommandTest::RunCommand(const CRhinoCommandContext& context)
{
	CRhinoGetObject go;
	go.SetCommandPrompt(L"Select Breps");
	go.EnableReferenceObjectSelect(false);
	go.EnableSubObjectSelect(false);
	go.EnableGroupSelect(true);

	go.SetGeometryFilter(ON::brep_object);
	go.GetObjects(1, 0);
	if (go.CommandResult() != CRhinoCommand::success)
		return go.CommandResult();
	ON_3dVector ve_move(5.0, 5.0, 0.0);
	ON_Xform xf_move = ON_Xform::TranslationTransformation(ve_move);
	ON_Xform xf_sc = ON_Xform::ScaleTransformation(ON_Plane::World_xy, 3.0, 3.0, 1.0);
	ON_2dexMap grmap;
	for (int i = 0; i < go.ObjectCount(); i++)
	{
		ON_Xform xf = xf_move * xf_sc;
		CRhinoHistory history(*this);
		WriteHistory(history, go.Object(i), xf);
		CRhinoObject* obj = RhinoApp().ActiveDoc()->TransformObject(
			go.Object(i), xf, false, false, false);
		if (obj != nullptr)
		{
			obj->SetHistory(history);
			RhinoUpdateObjectGroups(obj, grmap);
		}
	}
	return CRhinoCommand::success;
}

I mainly want to get transformation from the history record, but the TransformObject() funtion will cause rhino to crash when used it in history, That’s why I want to use the ON_Brep::Transform() function :smiley: