• PointInRange details please

    r20 c++
    3
    0 Votes
    3 Posts
    388 Views
    C4DSC
    @m_magalhaes said in PointInRange details please: But as you can see, this is pretty easy to create your own function, there's nothing fancy True, and I did. I just wanted to bring this up, as the documentation was rather ambiguous.
  • Buggy GeDialog Local2Global and Local2Screen

    c++ r20 r21
    8
    1
    0 Votes
    8 Posts
    956 Views
    C4DSC
    @r_gigante Sorry Riccardo, I do not understand your reply. I had tried with empty as well as non-empty dialogs. Both as DLG_TYPE::ASYNC and DLG_TYPE::ASYNC_POPUPEDIT. Still with these 4 combinations I do not get appropriate values for the global position. Bool MyDialog::CreateLayout() { Bool res = GeDialog::CreateLayout(); GroupBegin(0, BFH_SCALEFIT | BFV_SCALEFIT, 2, 0, ""_s, 0); AddButton(ACTION_1, BFH_CENTER | BFV_CENTER, 200, 10, "button A"_s); AddButton(ACTION_2, BFH_CENTER | BFV_CENTER, 300, 10, "button B"_s); AddEditText(ACTION_3, BFH_CENTER | BFV_CENTER, 500, 10); GroupEnd(); return res; } Bool MyCommand::Execute(BaseDocument* doc) { if (mDlg.IsOpen()) { mDlg.Close(); return true; } BaseContainer bc; if (GetInputState(BFM_INPUT_MOUSE, BFM_INPUT_MOUSELEFT, bc)) { const Int32 mx = bc.GetInt32(BFM_INPUT_X); const Int32 my = bc.GetInt32(BFM_INPUT_Y); const Int32 w = 50; const Int32 h = 50; mDlg.Open(DLG_TYPE::ASYNC /*ASYNC_POPUPEDIT*/, TEST_COMMAND_PLUGIN_ID, mx, my, w, h, 0); ApplicationOutput("Mouse cursor at @, @", mx, my); Int32 dlgX = 0; Int32 dlgY = 0; mDlg.Local2Screen(&dlgX, &dlgY); ApplicationOutput("Dialog created at @, @ (screen)", dlgX, dlgY); dlgX = 0; dlgY = 0; mDlg.Local2Global(&dlgX, &dlgY); ApplicationOutput("Dialog created at @, @ (global)", dlgX, dlgY); } return true; } Additionally, when activating the plugin when Cinema4D is fullscreen, the dialog gets positioned at the expected coordinates. But the position of the dialog is nowhere near the expected position if the plugin is activated when the Cinema4D window is not full screen. It seems as if the mouse coordinates relative to the application window are applied relative to the screen origin. Which means that if: 1 Cinema4D is not full screen 2 and offset from the top left corner of the screen by an amount X 3 assuming the mouse position is at coordinate mx from the Cinema4D's main window's top left corner The dialog ends up at mx from the screen's top left corner, instead of the expected X + mx. (All the above was tested with R20 only, since I have refrained from further R21 development) Unfortunately, I have moved on and am currently not focused on this particular plugin anymore. As such, I may have missed some details. I will need to find the time to pick up where I had left.
  • Rendering deformed Spline with Hair material

    c++
    19
    1 Votes
    19 Posts
    5k Views
    r_giganteR
    Hi @rsodre I'm sorry but I don't have any update on the bug resolution being it, as already stated, low-prio nor I can share bug-tracking information on a public forum. Best, R
  • Connecting Camera Focus Distance to Null Object with Python

    Moved python r21
    6
    1
    0 Votes
    6 Posts
    1k Views
    C
    @Cairyn Thanks for this fantastic resource, I will definitely use this summer to level up with Python.
  • Change parameter's unit type

    Moved python
    5
    0 Votes
    5 Posts
    810 Views
    bacaB
    @zipit thanks a lot, but based on c++ docs made this (seems there are just more checking): def GetDDescription(self, node, description, flags) : data = node.GetDataInstance() if data is None or not description.LoadDescription(node.GetType()): return False singleID = description.GetSingleDescID() paramID = c4d.DescID(c4d.DescLevel(c4d.TESTPLUGIN_OFFSET)) if ( singleID is None or paramID.IsPartOf(singleID)[0] ): bc = description.GetParameterI(paramID) if (bc): if data.GetLong(c4d.TESTPLUGIN_MODE) == TESTPLUGIN_MODE_DISTANCE: bc.SetLong(c4d.DESC_UNIT, c4d.DESC_UNIT_METER) else: bc.SetLong(c4d.DESC_UNIT, c4d.DESC_UNIT_PERCENT) return (True, flags | c4d.DESCFLAGS_DESC_LOADED)
  • Drawing Multiple Lines from TagPlugin

    s22 python sdk
    3
    1
    0 Votes
    3 Posts
    329 Views
    ?
    @zipit Hahahahaha! Thank you! I see my lines now. Who hoo!
  • BaseDraw in TagDataPlugin

    s22 python sdk
    3
    0 Votes
    3 Posts
    372 Views
    ?
    @m_adam My apologies for not being clearer. I thought there was something wrong with how I was doing the Draw function. The issue was the TAG_IMPLEMENTS_DRAW_FUNCTION flag was missing. Thank you very much!
  • Getting a list of objects at a given hierarchy

    2
    0 Votes
    2 Posts
    454 Views
    M
    Hi @nicholas_yue there is nothing builtin but the most optimized way I think will be import c4d def GetNodeListsAtCurrentLevel(bl2D): parent = bl2D.GetUp() if parent is None: parent = bl2D.GetListHead() return parent.GetChildren() def main(): print GetNodeListsAtCurrentLevel(doc.GetActiveTag()) # Execute main() if __name__=='__main__': main() Cheers, Maxime.
  • Render filtered Hardware Preview

    s22 classic api python
    10
    0 Votes
    10 Posts
    2k Views
    a_blockA
    Thanks for validating my assumptions. Much appreciated. Yes, I already have multiple code branches and for S22 my workaround looks as described. Because it doesn't hurt to insert the RenderData in this case, it doesn't even need multiple branches. Thanks for looking into it, Maxime. Is this going to be fixed in a future version?
  • CCurve.GetValue() with Track Before & After Functions

    python s22 sdk
    3
    1
    0 Votes
    3 Posts
    441 Views
    ?
    @m_magalhaes Remap did the trick! Thanks for the help, Manuel
  • How is NBIT_CKEY_ACTIVE used?

    python s22 sdk
    3
    0 Votes
    3 Posts
    258 Views
    ?
    @r_gigante Ahhhhhhhh, okay, I get it now. Thank you
  • This topic is deleted!

    1
    0 Votes
    1 Posts
    2 Views
    No one has replied
  • problem with loading plugin in python_init.py

    Moved
    3
    0 Votes
    3 Posts
    581 Views
    W
    @m_adam it's strange, but this small script works fine without any problems with cinema 4d s22. cinema 4d r20 show this error only.
  • Plugin affecting C4D modules startup

    c++ r20
    12
    2
    0 Votes
    12 Posts
    5k Views
    rsodreR
    @mmustafasarikaya See @m_adam reponse above. Deleting those files fixed the problem.
  • pop-up dialog windows and c4dpy : the problem

    Moved
    3
    0 Votes
    3 Posts
    747 Views
    M
    Hi @wob unfortunately this is not possible, c4dpy is a regular Cinema 4D executed as command line with the NoGui, and as all NoGui Cinema 4D execution, GeDialog is disabled. So its a limitation, and as said by zipit there is no Tkinter shipped with Cinema 4D in order to force people to use Cinema 4D dialog. So possible workarounds are: Install pip and install any 3rd party GUI module (but this is not officially supported by Cinema 4D so you may have some odd issues, but it should work). Execute a python script before from a system python installation that will create the Dialog and later execute c4dpy to do the Cinema 4D work. Cheers, Maxime.
  • any way to close cinema 4d from the python script

    Moved
    4
    0 Votes
    4 Posts
    870 Views
    M
    Hi @wob there is noting built-in for that in Cinema 4D. but you can use the regular python way to kill the current process import signal import os os.kill(os.getpid(), signal.SIGTERM) But I just let you know, that it may be useless by nature python should be pretty good at not creating any memory leak, and should free the data as soon as possible, moreover your approach ( I don't know the whole pipeline) but may also be a big issue for a user since this will clause Cinema 4D without asking for saving. People may lose their work. So I really encourage you to be very careful with the use of this. Cheers, Maxime.
  • Set Spline Tangents with Python Generator

    3
    0 Votes
    3 Posts
    1k Views
    J
    @zipit said in Set Spline Tangents with Python Generator: > """Example for constructing smooth tangents in a bezier spline. > > Run this with a spline object selected that has at least three vertices. It > will set the tangents of the second vertex of the spline in respect to its > neighbors. > """ > > import c4d > > > def project_on_line(p, a, b): > """Projects the point p onto the line which contains the line segment ab. > > Args: > p (c4d.Vector): The point to project. > a (c4d.Vector): The first point of the line segment. > b (c4d.Vector): The second point of the line segment. > > Returns: > c4d.Vector: The projection of p onto the line described by the line > segment ab. > """ > # Not much to explain here, check a trigonometry textbook on point line > # projections / the dot product if you are lost. > ab = b - a > t = ((p - a) * ab) / ab.GetLengthSquared() > return a + ab * t > > > def construct_vertex_frame(p, q, r): > """Constructs a frame for a spline vertex and its two normalized tangent > lengths. > > Args: > p (c4d.Vector): The point of the vertex for which to construct the > frame. > q (c4d.Vector): The point of the vertex which is the vertex before p. > r (c4d.Vector): The point of the vertex which is the vertex after p. > > Returns: > float, float, c4d.Vector: The normalized length of the left and > right tangent and the frame. > """ > > # The Vectors pointing from p to q and from p to r. > a, b = q - p, r - p > > # Now we construct our frame axis, I did use axis labels instead of the > # terms normal, binormal and tangent to keep things unambiguous. > > # The x-axis or tangent of the frame, i.e. the axis along which we will > # place out tangent control points. > x = (r - q).GetNormalized() > # The z-axis or normal of the frame, which is the normal to the plane > # of the three points. We just take the cross product of two vectors that > # lie in that plane. > z = (x % a).GetNormalized() > # The y axis or binormal of the frame, we just build it with the two > # other axis. > y = (x % z).GetNormalized() > # The finished matrix/frame. It is important to set the offset to the > # zero vector and not p, since each tangent pair lives in its own tangent > # space relative to their vertex. > frame = c4d.Matrix(c4d.Vector(), x, y, z) > > # We are technically finished here, but we could do some more, as we > # will have to determine the length of each tangent. We could just set > # these to a fraction of the vectors a, b, but this will give us odd > # results when theta, the angle between a and b is getting smaller and > # smaller. Instead we will project both a and b onto x and return the > # lengths of those two projections as the normalized length for the > # respective tangent. > origin = c4d.Vector() > tlength_left = project_on_line(a, origin, x).GetLength() > tlength_right = project_on_line(b, origin, x).GetLength() > > # Return the length of the left and right tangent and the frame. > return tlength_left, tlength_right, frame > > > def align_tangents(node, i, rel_scale_left=.5, rel_scale_right=.5): > """Aligns the tangents of a spline at a given index. > > Calculates the frame for the given vertex and sets its tangents for a > smooth interpolation in respect to its two neighbors. Will also force > the spline into bezier mode. > > Note: > This currently cannot handle the first and last vertex. It is trivial > to implement this, but things would have gotten more bloated, so I > kept short and (slightly) flawed. > > Args: > node (c4d.SplineObject): The spline. > i (int): The index of the vertex to align the tangents for. Has to > satisfy "0 < i < vertex_count - 1". > rel_scale_left (float, optional): The relative scale of the left > tangent. Defaults to 50%. > rel_scale_right (float, optional): The relative scale of the right > tangent. Defaults to 50%. > > Raises: > TypeError: When 'node' is not a SplineObject. > ValueError: When 'i' is out of bounds. > """ > if not isinstance(node, c4d.SplineObject): > raise TypeError("Expected SplineObject as input.") > > points = node.GetAllPoints() > # Out of bounds condition for the spline vertex indices. > if i < 1 or len(points) < i + 1: > raise ValueError("Index out of bounds.") > > # The three consecutive spline vertices that form the plane. p is > # the mid vertex for which we want to set the tangents and q and r > # are the vertices previous and next to it. > q, p, r = points[i-1:i+2] > # The normalized length of the tangents and the frame. > tlength_left, tlength_right, frame = construct_vertex_frame(p, q, r) > > # Constructing the tangents: > tangent_left = c4d.Vector(-tlength_left * rel_scale_left, 0, 0) * frame > tangent_right = c4d.Vector(tlength_right * rel_scale_right, 0, 0) * frame > > # Update the spline. > if node[c4d.SPLINEOBJECT_TYPE] is not c4d.SPLINETYPE_BEZIER: > node[c4d.SPLINEOBJECT_TYPE] = c4d.SPLINETYPE_BEZIER > node.SetTangent(i, tangent_left, tangent_right) > node.Message(c4d.MSG_UPDATE) > > # For visualization purposes we insert the frame of our vertex as a > # null object. SHOULD BE COMMENTED OUT. > null = c4d.BaseList2D(c4d.Onull) > null.SetMg(frame) > null.SetName("frame_for_vertex_" + str(i)) > doc.InsertObject(null) > > # Push the changes to Cinema. > c4d.EventAdd() > > > def main(): > """Entry point. > """ > # ALign the tangents of the second vertex of the selected spline object. > if op: > align_tangents(op, 1) > > > if __name__ == "__main__": > main() This was extremely helpful, thank you very much. My 3d geometry / Calc III is pretty rusty and seeing this really helped.
  • Catching when an ID collision occurs

    c++ sdk
    5
    0 Votes
    5 Posts
    571 Views
    D
    Thanks, this is exactly what I needed!
  • Render to PV / Video Post plugin

    c++
    12
    0 Votes
    12 Posts
    2k Views
    WickedPW
    @PluginStudent Thanks , progress bar sorted. For anyone reading, cast the vpBuffer into a Bitmap and use SetData(). Re GetDDescription(), I hard code my descriptions, but the function is never called. Any ideas? WP.
  • Get all neighboring points (including not connected by edge). Fast.

    python
    5
    0 Votes
    5 Posts
    1k Views
    ManuelM
    hi, from time to time i'm saying thanks to @zipit , but for sure he's contributing a lot to the community. there's not too much to say more that what have been said. Brut force is the only option without using external python librairies. You can always use an external library if you want to use a kd-tree structure to be faster. Using cpp would be a better solution if you really want to do it fast. We have in our API a kd-tree as show in this kd-stree manual. You can see on github a full example on how to use it And here are some code of me playing with different way of sampling a kd-tree using parallel method and also using voxelization to get the closest polygon. //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- /// GetClosestPolygon using voxelization //---------------------------------------------------------------------------------------- static maxon::Result<void> GETCLOSEST_POLY(BaseDocument* doc) { iferr_scope; if (doc == nullptr) return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION); // ------- Create a mesh with one poly const maxon::Int32 polyCnt{ 500 }; PolygonObject *mesh = PolygonObject::Alloc(polyCnt * 4, polyCnt ); if (mesh == nullptr) return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION); maxon::LinearCongruentialRandom<maxon::Float32> random; CPolygon *polyAdrW = mesh->GetPolygonW(); Vector* padrW = mesh->GetPointW(); const Float polySize{ 10 }; for (maxon::Int i = 0; i < polyCnt; i++) { CPolygon poly; maxon::Vector pointA(i * polySize, 0, 0); maxon::Vector pointB(i * polySize, 0, polySize); maxon::Vector pointC(i * polySize + polySize, 0, polySize); maxon::Vector pointD(i * polySize + polySize, 0, 0); const maxon::Int pointIndice = i * 4; padrW[pointIndice] = pointA; padrW[pointIndice + 1] = pointB; padrW[pointIndice + 2] = pointC; padrW[pointIndice + 3] = pointD; poly.a = pointIndice; poly.b = pointIndice + 1; poly.c = pointIndice + 2; poly.d = pointIndice + 3; polyAdrW[i] = poly; } doc->InsertObject(mesh, nullptr, nullptr); maxon::DistanceQueryRef distanceQueryRef = maxon::DistanceCalculator().Create() iferr_return; distanceQueryRef.Init(mesh, true) iferr_return; maxon::PrimitiveInformation result; const maxon::Int samplePointCnt = polyCnt; //---------------------------------------------------------------------------------------- /// sample using standard loop maxon::TimeValue start = maxon::TimeValue(maxon::TimeValue::NOW); for (maxon::Int i = 0; i < samplePointCnt; ++i) { const maxon::Vector pos{ i * polySize + polySize * 0.5, 0, 0 }; distanceQueryRef.GetClosestMeshPrimitive(pos, result); if (result.type == maxon::PRIMITIVETYPE::POLYGON) ApplicationOutput("pos @, polyIndex @ ", pos, result.GetRealPolyIndex()); else ApplicationOutput("not a polygon"); } ApplicationOutput("time to sample the points @ with MP", start.Stop()); //---------------------------------------------------------------------------------------- /// sample using parallelFor start = maxon::TimeValue(maxon::TimeValue::NOW); maxon::BaseArray< maxon::PrimitiveInformation> resultArray; resultArray.Resize(samplePointCnt) iferr_return; maxon::ParallelFor::Dynamic(0, samplePointCnt, [&resultArray, &polySize, &distanceQueryRef](maxon::Int i) { maxon::PrimitiveInformation result; const maxon::Vector pos{ i * polySize + polySize * 0.5, 0, 0 }; distanceQueryRef.GetClosestMeshPrimitive(pos, result); if (result.type == maxon::PRIMITIVETYPE::POLYGON) ApplicationOutput("pos @, polyIndex @ ", pos, result.GetRealPolyIndex()); else ApplicationOutput("not a polygon"); resultArray[i] = result; } ); ApplicationOutput("time to sample the points @ with MP", start.Stop()); for (auto& value : resultArray) { if (value.type == maxon::PRIMITIVETYPE::POLYGON) ApplicationOutput("polyIndex @ ", value.GetRealPolyIndex()); else ApplicationOutput("not a polygon"); } return maxon::OK; } //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- /// Sample a KD tree with multi thread //---------------------------------------------------------------------------------------- class SampleTreeJob : public maxon::JobInterfaceTemplate<SampleTreeJob, maxon::Int> { public: SampleTreeJob() { }; MAXON_IMPLICIT SampleTreeJob(maxon::KDTree* kdtree, const maxon::Vector& samplePoint) { _kdtree = kdtree; _samplePoint = samplePoint; } // function operator with the actual workload maxon::Result<void> operator ()() { maxon::Int nearestIndex = _kdtree->FindNearest(maxon::JobRef::GetCurrentWorkerThreadIndex(), _samplePoint, nullptr); // store result return SetResult(std::move(nearestIndex)); } private: maxon::KDTree* _kdtree; maxon::Vector _samplePoint; }; static maxon::Result <maxon::BaseArray<maxon::Vector>> CreateArrayOfPoints() { iferr_scope; const maxon::Int pointCnt = 1000000; maxon::BaseArray<maxon::Vector> points; points.EnsureCapacity(pointCnt) iferr_return; maxon::LinearCongruentialRandom<maxon::Float32> random; for (maxon::Int i = 0; i < pointCnt; ++i) { maxon::Vector pos(maxon::DONT_INITIALIZE); pos.x = random.Get01() * 100000.0; pos.y = random.Get01() * 100000.0; pos.z = random.Get01() * 100000.0; points.Append(pos) iferr_return; } return points; } static maxon::Result<maxon::BaseArray<maxon::Vector>> CreateSamplePoints() { iferr_scope; // sample points const maxon::Int samplePointCnt = 10000; maxon::BaseArray<maxon::Vector> samplePoints; samplePoints.EnsureCapacity(samplePointCnt) iferr_return; for (maxon::Int i = 0; i < samplePointCnt; ++i) { const maxon::Vector pos{ i* 10.0 }; samplePoints.Append(pos) iferr_return; } return samplePoints; } static maxon::Result<void> KDTREE_MP(BaseDocument* doc) { iferr_scope; maxon::BaseArray<maxon::Vector> points = CreateArrayOfPoints() iferr_return; maxon::BaseArray<maxon::Vector> samplePoints = CreateSamplePoints() iferr_return; const maxon::Int samplePointCnt = samplePoints.GetCount(); const maxon::Int pointCnt = points.GetCount(); maxon::KDTree tree; tree.Init(maxon::JobRef::GetCurrentThreadCount()) iferr_return; // insert points for (maxon::Int i = 0; i < pointCnt; ++i) { tree.Insert(points[i], i) iferr_return; } // balance tree tree.Balance(); //---------------------------------------------------------------------------------------- /// sample using classic loop maxon::TimeValue start{ maxon::TimeValue::NOW }; for (const maxon::Vector& samplePoint : samplePoints) { // find nearest point const maxon::Int nearestIndex = tree.FindNearest(0, samplePoint, nullptr); } ApplicationOutput("time to sample the points @ ", start.Stop()); //---------------------------------------------------------------------------------------- /// sample using parallelFor start = maxon::TimeValue(maxon::TimeValue::NOW); maxon::ParallelFor::Dynamic(0, samplePointCnt, [&samplePoints, &tree](maxon::Int i) { const maxon::Vector samplePoint = samplePoints[i]; const maxon::Int nearestIndex = tree.FindNearest(maxon::JobRef::GetCurrentWorkerThreadIndex(), samplePoint, nullptr); } ); ApplicationOutput("time to sample the points @ with MP", start.Stop()); //---------------------------------------------------------------------------------------- /// Sample using job // create group start = maxon::TimeValue(maxon::TimeValue::NOW); maxon::JobGroupRef group = maxon::JobGroupRef::Create() iferr_return; for (auto i = 0 ; i < samplePointCnt; i++) { // create and add job const maxon::Vector samplePoint = samplePoints[i]; auto job = SampleTreeJob::Create(&tree, samplePoint) iferr_return; group.Add(job) iferr_return; } // enqueue jobs and wait group.Enqueue(); group.Wait(); ApplicationOutput("time to sample the points @ with jobs", start.Stop()); //---------------------------------------------------------------------------------------- /// sample using classic loop again start = maxon::TimeValue(maxon::TimeValue::NOW); for (const maxon::Vector& samplePoint : samplePoints) { // find nearest point const maxon::Int nearestIndex = tree.FindNearest(0, samplePoint, nullptr); } ApplicationOutput("time to sample the points @ second time to see if caches are envolved", start.Stop()); return maxon::OK; } Cheers, Manuel