Moving Sketch Points

Moving Sketch Points

Anonymous
Not applicable
3,053 Views
8 Replies
Message 1 of 9

Moving Sketch Points

Anonymous
Not applicable

I've written a control in C++ that lets me select a sketch point, return its XYZ vales and then edit the XYZ values; moving the sketch point to a new position. I need to keep the control open so that I can modify the position of more than one sketch pint........... usually five one at a time.

 

To keep the control active I use the execute preview event and a Boolean value input button to apply the changes to each sketch point. I'm using the input change even to capture the sketch points coordinates as I select each sketch point.

 

The problem occurs after changing the first sketch point, it move fine but as soon as I select the second sketch point the first point reverts back to its original position......... I just cannot get the change to a sketch point position to persist or activate the execute event from the execute preview event.

 

I did read a post explaining that Fusion doesn't have an "Apply" concept and you need to work around the problem with the Boolean value input......... It there any way to make the sketch point changes persist after selection change and after the control is close?

0 Likes
Accepted solutions (1)
3,054 Views
8 Replies
Replies (8)
Message 2 of 9

ekinsb
Alumni
Alumni

Each time the execute preview event fires, Fusion aborts whatever was done in the previous event so you can create the new preview.  To do what you want to do, each time the user clicks the button to move the currently selected point, you can add the point and the coordinate to a list variable and then save the selected sketch point and the coordinate into a global list.  Then in the execute preview you can iterate through the list and move all of the points to the position associated with it.

 

Because there isn't an "apply" or the ability to save an intermediate step, this also means that if the user clicks "Cancel" none of the moves are saved.  Clicked "OK" will save all of the changes as a single undo.


Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
0 Likes
Message 3 of 9

Anonymous
Not applicable

Hi Brian,

 

Thanks for the reply.

 

I had considered capturing the points and their movement vectors in a list that I could process on the execute event, when the Ok button is pressed.......... But here's the thing.

 

The sketch points control a sketch curve representing an objects movement path and the idea of my control is to let the user alter the path of the sketch curve and see the results before accepting or rejecting; sketch points jumping back to their original position, on selection change, just doesn't look good and doesn't help with the visualisation.

 

I had been hoping that the user could change the position of the sketch points using the Fusion move control, but that control only appears to let you add the distance you want to move and not the destination coordinates. The Fusion move control works great for course adjustment, but needs the user to calculate the translation vector when they require fine control; the idea behind my control was to allow the user to enter a destination and have the control calculate the translation vector for them.

 

Is there another event handler I could use or am I missing something, like maybe tapping into the Fusion move control? I've been using SolidWorks for the past 20 years and am relatively new to Fusion, so any pointers would be greatly appreciated.

 

Andrew 

0 Likes
Message 4 of 9

liujac
Alumni
Alumni

Hi,

 

You can try also move the cached sketch points to the cached positions in execute preview event, so that the sketch points won't jump back on selection change. If you still have problem, You'd better provide the sample code to demo the problem.

 

Thanks,

Jack

0 Likes
Message 5 of 9

Anonymous
Not applicable

Hi Jack,

 

When you say cached sketch points, I assume you mean that I need to look at their occurrence; occurrences are something I am still getting used to. I will give it a go and see what happens.

 

Thanks

Andrew

0 Likes
Message 6 of 9

Anonymous
Not applicable

Hi Jack,

 

I just cannot see how to get to any under lying cached data from a selected entity, here's how I am picking up the sketchPoint and using it......... can you help?

 

Ptr<Selection> selection;

class OnManualDefineMovementExecutePreviewEventHander : public adsk::core::CommandEventHandler
{
public:
	void notify(const Ptr<CommandEventArgs>& eventArgs) override
	{		
		if (moveButton->value())
		{
			if (selection)
			{
				Ptr<SketchPoint> selectedPoint = selection->entity();
				Ptr<Point3D> geometry = selectedPoint->worldGeometry();

				double selectedX = geometry->x();
				double selectedY = geometry->y();
				double selectedZ = geometry->z();

				double chosenX = xValueInput->value();
				double chosenY = yValueInput->value();
				double chosenZ = zValueInput->value();

				double requiredX = chosenX - selectedX;
				double requiredY = chosenY - selectedY;
				double requiredZ = chosenZ - selectedZ;

				// Move sketch point
				Ptr<Vector3D> translation = Vector3D::create(requiredX, requiredY, requiredZ);
				selectedPoint->move(translation);

				eventArgs->isValidResult(true);
			}
			else
			{
				Application::get()->userInterface()->messageBox("Plese select a sketch point");
			}
			// Reset the button's boolean value
			moveButton->value(false);
		}		
	}
};

class OnDefineMovmenentSelectionChangeEventHandler :public adsk::core::InputChangedEventHandler
{
public:
	void notify(const Ptr<InputChangedEventArgs>& eventArgs) override
	{
		if (eventArgs)
		{
			Ptr<SelectionCommandInput>cmdSelect = eventArgs->input();
			if (cmdSelect)
			{
				selection = cmdSelect->selection(0);
				if (selection)
				{
					Ptr<Base> base = selection->entity();
					string entityName = base->objectType();

					if (entityName == "adsk::fusion::SketchPoint")
					{
						Ptr<SketchPoint> selectedPoint = selection->entity();
						Ptr<Point3D> geometry = selectedPoint->worldGeometry();

						xValueInput->value(geometry->x());
						yValueInput->value(geometry->y());
						zValueInput->value(geometry->z());
					}
				}
				else
				{
					// Clear any selection values
					xValueInput->value(0);
					yValueInput->value(0);
					zValueInput->value(0);
					selection = NULL;
				}
			}
		}
	}
};

 

 

 

0 Likes
Message 7 of 9

ekinsb
Alumni
Alumni

I think the idea in my original response can be used to achieve what you want.  After some more thought, I don't think you need a button to do the "apply".  Here is the basic approach that I think can be used.

 

The approach I was suggesting is that during this invocation of the command you maintain a list of the points that have already been moved and the vector values for each one in a global list.  In the executePreview event handler you move the current point based on the x, y, and z values in the dialog but you also move all of the points in the global list based on the values you saved with each point.  With each preview you're moving all of the points that have been repositioned.

 

The list will contain the sketch point and the offset values.  You add this data to the list as the user selects points.  When a user selects a point, that becomes the "active" point.  You'll check to see if it's already in the list and if it is you'll initialize the dialog to use the values saved in the list for that point.  Also, when they select a point, if there's already an "active" point you'll add that point and it's offset information to the list. If they clear the selection (click the "x" besides the selection) you'll also add the active point to the list.

 

With this approach, the points are being updated as the values are edited in the dialog, so there's no need for an apply.

 

Another thing to keep in mind that you have mentioned yet, is that sketch points are defined in the coordinate system of the sketch, which might not always be logical.  If you want to move the point relative to the model coordinate system you can use modelToSketchSpace and sketchToModelSpace methods on the sketch to convert from one space to another. 


Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
0 Likes
Message 8 of 9

liujac
Alumni
Alumni

What I meant was same as Brian suggested. One more thing, you need to set the minimum limit of the selection input to 0, so that the execute preview event is also fired when clear the selection. I wrote the sample code as below.

 

namespace
{
	const std::string commandId_ = "myCommand_";
	const std::string selectionInputId_ = "selectionInput";
	const std::string xValueInputId_ = "xValueCommandInput";
	const std::string yValueInputId_ = "yValueCommandInput";
	const std::string zValueInputId_ = "zValueCommandInput";
	std::map<Ptr<SketchPoint>, Ptr<Point3D>> movedSketchPoints_;

	bool moveSketchPoint(Ptr<SketchPoint> skPt, Ptr<Point3D> newPos)
	{
		if(!skPt || !newPos)
			return false;

		if(newPos->isEqualTo(skPt->worldGeometry())) //No need to move
			return false;

		Ptr<Sketch> sk = skPt->parentSketch();
		if(!sk)
			return false;

		// Transfer the target position from model space to sketch space
		Ptr<Point3D> newPosInSk = sk->modelToSketchSpace(newPos);
		if(!newPosInSk)
			return false;

		Ptr<Point3D> originalPosInSk = skPt->geometry();
		if(!originalPosInSk)
			return false;

		Ptr<Vector3D> translation = originalPosInSk->vectorTo(newPosInSk);
		if(!translation)
			return false;

		return skPt->move(translation);
	}
}

Ptr<Application> app;
Ptr<UserInterface> ui;

class CommandExecutedHandler : public adsk::core::CommandEventHandler
{
public:
	void notify(const Ptr<CommandEventArgs>& eventArgs) override
	{
		Ptr<Event> firingEvent = eventArgs->firingEvent();
		if (!firingEvent)
			return;

		Ptr<Command> command = firingEvent->sender();
		if (!command)
			return;

		Ptr<CommandInputs> inputs = command->commandInputs();
		if(!inputs)
			return;

		for (auto movedPoint : movedSketchPoints_ )
		{
			moveSketchPoint(movedPoint.first, movedPoint.second);
		}

		eventArgs->isValidResult(true);

		Ptr<SelectionCommandInput> selInput = inputs->itemById(selectionInputId_);
		if(!selInput)
			return;

		Ptr<Selection> sel = selInput->selection(0);
		if(!sel)
			return;

		Ptr<SketchPoint> skPt = sel->entity();
		if(!skPt)
			return;

		double x = 0.0;
		double y = 0.0;
		double z = 0.0;
		Ptr<ValueCommandInput> xValue = inputs->itemById(xValueInputId_);
		if(xValue)
			x = xValue->value();

		Ptr<ValueCommandInput> yValue = inputs->itemById(yValueInputId_);
		if(yValue)
			y = yValue->value();

		Ptr<ValueCommandInput> zValue = inputs->itemById(zValueInputId_);
		if(zValue)
			z = zValue->value();

		Ptr<Point3D> newPos = adsk::core::Point3D::create(x, y, z);
		if(moveSketchPoint(skPt, newPos))
			movedSketchPoints_[skPt] = newPos;
	}
};

class InputChangedHandler : public adsk::core::InputChangedEventHandler
{
public:
	void notify(const Ptr<InputChangedEventArgs>& eventArgs) override
	{
		Ptr<Event> firingEvent = eventArgs->firingEvent();
		if (!firingEvent)
			return;

		Ptr<Command> command = firingEvent->sender();
		if (!command)
			return;

		Ptr<CommandInputs> inputs = command->commandInputs();
		if(!inputs)
			return;

		Ptr<SelectionCommandInput> cmdInput = eventArgs->input();
		if(!cmdInput)
			return;

		double x = 0.0;
		double y = 0.0;
		double z = 0.0;
		Ptr<Selection> sel = cmdInput->selection(0);
		if(sel)
		{
			Ptr<SketchPoint> skPoint = sel->entity();
			if(!skPoint)
				return;

			Ptr<Point3D> pt = movedSketchPoints_[skPoint];//Get the cached point if exists
			if(!pt)
				pt = skPoint->worldGeometry();
			if(!pt)
				return;

			x = pt->x();
			y = pt->y();
			z = pt->z();
		}
		
		Ptr<ValueCommandInput> xValue = inputs->itemById(xValueInputId_);
		if (xValue)
		{
			//xValue->value(x);
			std::stringstream ss;
			ss << x << "cm";
			xValue->expression(ss.str());
		}

		Ptr<ValueCommandInput> yValue = inputs->itemById(yValueInputId_);
		if (yValue)
		{
			std::stringstream ss;
			ss << y << "cm";
			yValue->expression(ss.str());
		}

		Ptr<ValueCommandInput> zValue = inputs->itemById(zValueInputId_);
		if (zValue)
		{
			std::stringstream ss;
			ss << z << "cm";
			zValue->expression(ss.str());
		}
	}
};

class CommandCreatedHandler : public adsk::core::CommandCreatedEventHandler
{
public:
	void notify(const Ptr<CommandCreatedEventArgs>& eventArgs) override
	{
		if (eventArgs)
		{
			Ptr<Command> command = eventArgs->command();
			if (!command)
				return;

			Ptr<CommandEvent> exec = command->executePreview();
			if (!exec)
				return;
			exec->add(&onCommandExecuted_);

			Ptr<InputChangedEvent> inputChanged = command->inputChanged();
			if (!inputChanged)
				return;
			inputChanged->add(&onInputChanged_);
			
			// Define the inputs.
			Ptr<CommandInputs> inputs = command->commandInputs();
			if (!inputs)
				return;

			Ptr<SelectionCommandInput> selInput = inputs->addSelectionInput(selectionInputId_, "Selection", "Select one sketch point");
			if (selInput)
			{
				selInput->setSelectionLimits(0, 1);//Set minimum limit to 0 means there is no minimum limit.
				selInput->addSelectionFilter("SketchPoints");
			}

			inputs->addValueInput(xValueInputId_, "X", "cm", ValueInput::createByString("0.0 cm"));
			inputs->addValueInput(yValueInputId_, "Y", "cm", ValueInput::createByString("0.0 cm"));
			inputs->addValueInput(zValueInputId_, "Z", "cm", ValueInput::createByString("0.0 cm"));
		}
	}
private:
	CommandExecutedHandler onCommandExecuted_;
	InputChangedHandler onInputChanged_;
};
static CommandCreatedHandler onCommandCreated_;

Regards,

Jack

0 Likes
Message 9 of 9

Anonymous
Not applicable
Accepted solution

Hi Jack, Hi Brain,

Thank you both for all the help, I just about have Jacks sample up and running. I think there is enough here for me to work with so lets call this one solved.

 

Thanks again.

 

Andrew

0 Likes