A simple question


#1

In .Net C#,There is a function about IShapeObject.It is “AttachShape”.You know there is very little information on the API .my codes are following:

//spls is List
IINode Aspl = spls[0];
IINode Bspl = spls[1];
IObject obj = Aspl .ObjectRef;
IShapeObject spl = (IShapeObject)obj;
bool bl = spl.AttachShape(t, Aspl, Bspl, true, 0);

The “bl” will always be false.I Spent a day on it, a little lost.Whether can experts give the correct method.


#2

I’ve checked the sources and none of maxscript functions use this AttachShape method, instead AddAndWeld of IBezierShape class is used to combine shapes.
Also when you use ‘Attach’ button to pick spline to attach from the viewport it uses DoAttach method of ISplineShape class
So perhaps you’ll have to choose between these two


#3

object.h -> ShapeObject::AttachShape

but when I look into my code, I see that I am using my own attach shape methods instead of the built-in one. Of course there was a reason for this.


#4

Neither of these methods is simple; the first requires a transformation matrix,The second way I don’t know “ref canUndo” parameter.I think denisT’s method is more appropriate.@Serejah,What do you think?


#5

I’m far from being an expert in anything sdk related.
It seems like these transforms and matrixes are the problem for you at the moment. All of these methods I mentioned above use transforms and matrixes to do what has to be done (i’ve checked the sources). Maybe it is worth spending some time to deal with them instead of looking for a workaround. As a last resort you can always call maxscript from c# if it is something unbearable :smile:


#6

Yes,I’ve been using Maxscripts to write something.It was later found to have significant limitations, although it was relatively simple.So I try using c# or c++,Although this attempt is difficult, it can solve many problems,For example, speed issues,I think I have a long way to go.


#7

The AttachShape method is virtual and cannot be used on its own… Developers of a shape geometry class must provide an implementation of it if they expect the class to have attachment functionality. That’s why you always get FALSE as a result, which means AttachMethod is not implemented, so I use my own.


#8

from the SDK (editspl.cpp)

static void DoAttach(BezierShape *shape, BezierShape *attShape, int mtlOffset) {
   int boff = shape->splineCount;
   for(int i = 0; i < attShape->splineCount; ++i) {
      int index = shape->splineCount;
      Spline3D *spline = shape->NewSpline();
      *spline = *(attShape->splines[i]);
      for(int seg = 0; seg < spline->Segments(); ++seg)
         spline->SetMatID(seg, spline->GetMatID(seg) + mtlOffset);
      shape->vertSel.Insert(shape->splineCount-1,spline->Verts());
      shape->segSel.Insert(shape->splineCount-1,spline->Segments());
      shape->polySel.Insert(shape->splineCount-1);
      shape->vertSel[index] = attShape->vertSel[i];
      shape->segSel[index] = attShape->segSel[i];
      shape->polySel.Set(index, attShape->polySel[i]);
      // Flush all aux data in attached spline (prevents ResolveTopoChanges problems)
      for(int j = 0; j < spline->KnotCount(); ++j)
         spline->SetAux2(j, -1);
      }
//copy over binds + offset
   for (int i = 0; i < attShape->bindList.length();i++)
      {
      attShape->bindList[i].pointSplineIndex += boff;
      attShape->bindList[i].segSplineIndex += boff;
      

      shape->bindList.append(attShape->bindList[i]);
      }
   for (int i = 0; i < shape->bindList.length();i++)
      {
      int index = 0;
      int spindex = shape->bindList[i].pointSplineIndex;
      if (shape->bindList[i].isEnd)
            index = shape->splines[spindex]->KnotCount()-1;
      shape->bindList[i].bindPoint = shape->splines[spindex]->GetKnotPoint(index);
      shape->bindList[i].segPoint = shape->splines[spindex]->GetKnotPoint(index);

      }

   }

this is what you have to do to attach a BezierShape

DoAttach is a generic method for all node attachment types. It is responsible for the “node” related (material, transform, etc.) attachment tasks, and usually doesn’t do anything related to the “object things” (geometry, topology, etc.).


#9

Great,I also found it in the SDK example, I need to rewrite it to c# code.There is also a problem if those Bezier Shapes come from two different nodes,Do we need to transform their corresponding matrix?


#10

It depends on what you want to get. But usually we expect the end result to look exactly the same as everything looked before attaching. So, yes, we have to transform the attached object in the space of the main node.


#11

I rewrite them :

        int boff = shape.SplineCount;
        for (int i = 0; i < attShape.SplineCount; ++i)
        {
            int index = shape.SplineCount;
            ISpline3D spline = shape.NewSpline(0, 1, 0);
            spline = attShape.GetSpline(i);
            for (int seg = 0; seg < spline.Segments / 3; ++seg)
                spline.SetMatID(seg, (ushort)(spline.GetMatID(seg) + mtlOffset));
            shape.VertSel.Insert(shape.SplineCount - 1, spline.Verts);
            shape.SegSel.Insert(shape.SplineCount - 1, spline.Segments);
            shape.PolySel.Insert(shape.SplineCount - 1);
            shape.VertSel = attShape.VertSel;
            shape.SegSel = attShape.SegSel;
            shape.PolySel.Set(index, attShape.PolySel[i]);

            for (int j = 0; j < spline.KnotCount; ++j)
                spline.SetAux2(j, -1);
        }
        //copy over binds + offset
        for (uint i = 0; i < attShape.BindList.Length; i++)
        {
            attShape.BindList[i].PointSplineIndex += boff;
            attShape.BindList[i].SegSplineIndex += boff;


            shape.BindList.Append(attShape.BindList[i]);
        }
        for (uint i = 0; i < shape.BindList.Length; i++)
        {
            int index = 0;
            int spindex = shape.BindList[i].PointSplineIndex;
            if (shape.BindList[i].IsEnd)
                index = shape.GetSpline(spindex).KnotCount - 1;
            shape.BindList[i].BindPoint = shape.GetSpline(spindex).GetKnotPoint(index);
            shape.BindList[i].SegPoint = shape.GetSpline(spindex).GetKnotPoint(index);

        }

These are my test code:

                //spls is List<IINOde>
                IObject sobj = spls[0].ObjectRef;
                ISplineShape spl = (ISplineShape)sobj;
                IBezierShape bzSpl = spl.Shape;

                for (int i = 1; i < spls.Count; i++)
                {
                    ISplineShape nextspl = (ISplineShape)spls[i].ObjectRef;
                    SRYDoAttach(bzSpl, nextspl.Shape,0);
                 }
                bzSpl.UpdateSels(true);
                bzSpl.InvalidateGeomCache();

There is not any change for two splineshape s in my scene.Why?(using redraw views)


#12

worth checking how it is implemented in EditSplineMod::DoAttach in editspl.cpp

btw, do you really have to re implement all of these basic methods ?
Just curious what king of a plugin you’re making that requires that. Most likely you won’t get much performance improvement over using what’s already there, I mean DoAttach and others


#13

I used Maxscript to write a complex plugin,You’ll find that the base methods available to you are very limited.
For example, we use the “AddAndWeld” to attach some splineshape s.There are a lot of knots above them that are very close together,They are open and we don’t need them to be welded together.Otherwise the rest of the work is wrong.That’s when"AddAndWeld" seems powerless.So we had to build these most basic methods.
I know there’s a way (DoAttach)in Splineshape,I did, but it didn’t work.Maybe I didn’t understand meaning of this parameter:ref bool canUndo.

//spl is splineshape
bool undo = false;
spl.DoAttach(spls[i], ref undo);


#14

CanUndo does exactly what it says. It is an option to make the attach operation undoable or not. Because the Undo Restore entry for attaching a spline can take quite a lot of memory.


#15

Can you give me an example that works,My codes don’t work, Miraculous


#16

your code seems correct to me…maybe it needs some updating. I do ComputeBezPoints for all Spline3Ds, and do InvalidateGeomCache for SplineShape object.

Because in Attach operations usually involves nodes, before DoAttach you have to delete attaching node.


#17

If you want just to attach shapes I see no problem here. Use negative weld threshold and that’s it

gif

Default max text where every segment is detached. All copies are placed exactly above one another.
I made extra copy of the yellow one to show that it works even when segments overlay each other perfectly. Hope that helps

while selection.count > 1 and not keyboard.escPressed do addAndWeld selection[1] selection[2] -1


#18

I had to keep exploring,Thanks for the answer anyway,@denisT,@Serejah.You made me understand the meaning of -1 value.