Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a POINT_N_COPY from a Vector? #718

Closed
phkahler opened this issue Sep 26, 2020 · 11 comments
Closed

Create a POINT_N_COPY from a Vector? #718

phkahler opened this issue Sep 26, 2020 · 11 comments
Assignees
Labels

Comments

@phkahler
Copy link
Member

I'm writing code to import IDF files. It's working ok, but all the points are regular points created by calling one of:

SS.GW.AddRequest(Request::Type::LINE_SEGMENT, /*rememberForUndo=*/false);
SS.GW.AddRequest(Request::Type::ARC_OF_CIRCLE, /*rememberForUndo=*/false);
SS.GW.AddRequest(Request::Type::CIRCLE, /*rememberForUndo=*/false);

The problem with that is each point has 3 DoF in the solver and that function not only creates a line entity, it creates two point entities. I'd rather do two things:

  1. Create lines and points separately so adjoining lines can share a point via the same handle (hEntity)
  2. Make the points of type POINT_N_COPY and just set their numeric coordinates directly

I've been trying to make these new functions work:

hEntity newFixedPoint(Vector p) {
    Entity point = {};
    point.type = Entity::Type::POINT_N_COPY;
    point.numPoint = p;
    point.construction = false;
//    point.style = something;
    point.group = SS.GW.activeGroup;
    point.h = SK.entity.AddAndAssignId(&point);
    return point.h;
}

hEntity newFixedLine(hEntity p0, hEntity p1) {
    Entity line = {};
    line.type = Entity::Type::LINE_SEGMENT;
    line.point[0] = p0;
    line.point[1] = p1;
    line.construction = false;
//    line.style = something GetStyle();
    line.group = SS.GW.activeGroup;
    line.h = SK.entity.AddAndAssignId(&line);
    return line.h;
}

With those functions I want to change my line creation code like this: (the commented lines work)

     Vector p0 = Vector::From(x1, y1, 0.0);
     Vector p1 = Vector::From(x2, y2, 0.0);

     hEntity pa = newFixedPoint(p0);
     hEntity pb = newFixedPoint(p1);
     newFixedLine(pa,pb);
//        hRequest hr = SS.GW.AddRequest(Request::Type::LINE_SEGMENT, /*rememberForUndo=*/false);
//        SK.GetEntity(hr.entity(1))->PointForceTo(p0);
//        SK.GetEntity(hr.entity(2))->PointForceTo(p1);

The existing way works and is similar to DXF import, but it creates disconnected entities. DXF import constrains coincident points, but I'd rather just use the same points and have zero DoF by using POINT_N_COPY type. I can make lines share points after this direct replacement is working. Also, where can I get the correct style from? It seems like every place in the code that sets a style member copies another one which I don't have here.

@phkahler
Copy link
Member Author

BTW functional board outline importer here:
https://github.com/phkahler/solvespace/tree/idf-import
Sample file attached (grabbed from a forum somewhere)
xyz.zip

@jwesthues
Copy link
Member

If you want the thing you import to be editable, then POINT_N_COPY doesn't do what you want. Without big architectural changes, your only option is to create requests (as you're doing now), and then perhaps automatically generate some constraints to hold the shared endpoints together. The requests then generate the endpoint and line entities. (The request and group structure of a file is saved. The entity structure is not; they all get regenerated when the file is opened.)

If you don't want it to be editable, then you could just handle it the same as linked .slvs files, with a special group. Then you could directly generate POINT_N_ROT_TRANS, and from there generate the entities you want, sharing endpoints however you prefer. Those entities wouldn't be editable, but could be constrained against, extruded, etc.

The default for anything a user draws is NO_STYLE, and that should be fine for you too.

@phkahler
Copy link
Member Author

@jwesthues I don't want it to be editable. Probably should look at how linking works and do that instead. So when linking a file, all the entities are Generated from requests - I didn't realize that. Are the groups Solved as well? Where do these groups from the linked file exist while their SShells, SMeshes, and Entities are being generated? What are the N_ROT_TRANS entities copied from? All that appears in the text window is a single new group.

Pointers as to where I need to hook in to do this a simply as possible would be appreciated. I can read enough of the files now so it's just a matter of what to do with the data.

@phkahler
Copy link
Member Author

So the files clearly contain entities and there's LoadEntitiesFromFile() which is called from ReloadAllLinked() which I assume loads entities from linked files. And groups have a member vector named "impEntity" which seems to be where they get read into. In Group::Generate() we see that entities are copied from impEntity by pointer, so the imported/linked entites are not part of the global sketch until those copies are made for the linked group. Linked groups don't seem to have a list of imported requests.

So I could create the impEntitys similar to how I was trying before but put the coordinates in the actPoint which is what gets copied from. Could do that twice, once for each side of the board. Creating the impShell may or may not be possible.

By keeping the import option we can create the entities via requests and make the extrusion too. The user could then save that as .slvs and link it to get the 3D version of the board for assembly.

@jwesthues
Copy link
Member

Sorry, my explanation above was incomplete. A .slvs file certainly does contain the entities, but those are used only when the file is linked / assembled. When the file is opened itself, the entities gets regenerated from the requests and groups, and the entities saved in the file are totally ignored. You are correct that requests are ignored when we link (since the only purpose of the requests is to generate the entities, and we're using the saved entities instead of regenerating ourselves). Like the entities, the solid model (triangle or NURBS) is also saved in the .slvs file and used when a part is linked into an assembly, but regenerated from the requests and groups when the part itself is opened.

Any entities that you create last only until the next GenerateAll(). So when you import/link that IDF file, you need to not only create the desired entities, but also create them in a way that will persist across that regeneration. So your options are to:

  1. Create a request for each entity, like you're doing now. This makes the imported thing editable (same as if the user had drawn the entities by hand), but indeed creates lots of free solver parameters. Per above, you could automatically generate some point-coincident constraints to cut that in ~half. You could also create 2d points in workplane instead of 3d points if a workplane is selected.
  2. Or, create a single group that tells SolveSpace that next time it regenerates, it should re-read the IDF file and re-create the entities. This is basically how link/assemble works now for .slvs files, and LoadEntitiesFromFile() is indeed the right place to start. To implement this option, I'd probably use the same LINKED group type, and extend the file-loading routines to support file formats other than .slvs. This would also extend naturally to STEP, STL, etc. import. The current LINKED group has six solver DOF (four parameters for a quaternion, plus three for a vector, minus one automatic constraint normalizing the quaternion to unit length) that allow the user to freely rotate and translate the imported thing in space.

Does the IDF file format contain any kind of persistent identifiers for each point (so that e.g. if you modified a square outline to add a notch in one side, the four corner points of the overall square would keep the same identifiers)? If yes, then option (2) would let you keep associativity across changes to the board outline (i.e., load the new outline with the notch while constraints against the old corner points still applied to the new corner points), if you used something like the remap mechanism to make the map from that identifier to the hEntity consistent.

Otherwise I suspect that (2) has little benefit over (1), and loses some flexibility--you can simulate option (2) except for the associativity by importing the IDF file into an otherwise blank .slvs file and the linking/assembling that .slvs file, but option (2) makes it fundamentally impossible for the user to edit the outline. For file formats where we have no reasonable user interface for editing (e.g., STL, STEP), that's no loss, but here perhaps it would be. Either way seems reasonable to me, though.

@phkahler
Copy link
Member Author

Does the IDF file format contain any kind of persistent identifiers for each point

No, it's just a list of lines, arcs, and circles. They do group them by loop number (they form closed curves), and there is a separate section for drilled holes, but nothing that really looks like it would be persistent if someone moved or added a component. Mounting holes are specifically identified as such, but not uniquely identified. It might be reasonable to assume those get written in the same order but even that depends on the tool that writes the file.

This is a good exercise and should result in a very simple code demo of linking other formats.

Not sure STEP is any better about persistent IDs than IDF, a tool could persist IDs across saves but I suspect they just write those like line numbers in order to tie points to curves and curves to surfaces strictly within the file. Unless there's some unique ID that I didn't notice while trying and failing to write colors info into STEP.

@jwesthues
Copy link
Member

Got it, seems like no associativity in any case then. I guess the thorough option would be to provide both (1) and (2) for file formats that we do have a reasonable user interface to edit (like DXF or IDF, or STEP excluding surfaces), and only option (2) otherwise (like STL or STEP including surfaces)? More work, but maybe not that much since most of the effort is correctly parsing the file.

@phkahler
Copy link
Member Author

@jwesthues I've add code intended to Link and IDF file. It's expected to create verticies for line end points and hole centers, but nothing appears on screen. The linking code is past line 250 in importidf.cpp and is similar to the Import, but it doesn't seem to work. I'm hoping you can have a look, as I'm all out of ideas about what's wrong. It does add 30 entities to the list when linking the file xyz.emn in the zip file several comments back, but nothing shows up.

Current branch is here: https://github.com/phkahler/solvespace/tree/idf-import

Points need to work first, as lines and arcs will reference them by handle. Circles are going to need working points, normals, and distances.

I will probably remove IDF import, as it seems like a very low value thing to do. The point is to allow MCAD to build things that fit a design from ECAD and verify fit.

@phkahler
Copy link
Member Author

@jwesthues please disregard, I had to set actVisible = true and forceHidden = false and now the points show up.

@jwesthues
Copy link
Member

Cool, makes sense. Those are the flags that make it so an entity hidden in the part is always hidden in the assembly (even when the part is shown in the assembly), so they're not relevant for an input file format with no such concept.

@phkahler
Copy link
Member Author

Closing to reduce the number of open issues.
The details are covered in PR #725 implementing IDF file linking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants