void Group::MenuGroup(int id) { Group g; ZERO(&g); g.visible = true; g.color = RGBi(100, 100, 100); g.scale = 1; if(id >= RECENT_IMPORT && id < (RECENT_IMPORT + MAX_RECENT)) { strcpy(g.impFile, RecentFile[id-RECENT_IMPORT]); id = GraphicsWindow::MNU_GROUP_IMPORT; } SS.GW.GroupSelection(); switch(id) { case GraphicsWindow::MNU_GROUP_3D: g.type = DRAWING_3D; g.name.strcpy("sketch-in-3d"); break; case GraphicsWindow::MNU_GROUP_WRKPL: g.type = DRAWING_WORKPLANE; g.name.strcpy("sketch-in-plane"); if(gs.points == 1 && gs.n == 1) { g.subtype = WORKPLANE_BY_POINT_ORTHO; Vector u = SS.GW.projRight, v = SS.GW.projUp; u = u.ClosestOrtho(); v = v.Minus(u.ScaledBy(v.Dot(u))); v = v.ClosestOrtho(); g.predef.q = Quaternion::From(u, v); g.predef.origin = gs.point[0]; } else if(gs.points == 1 && gs.lineSegments == 2 && gs.n == 3) { g.subtype = WORKPLANE_BY_LINE_SEGMENTS; g.predef.origin = gs.point[0]; g.predef.entityB = gs.entity[0]; g.predef.entityC = gs.entity[1]; Vector ut = SK.GetEntity(g.predef.entityB)->VectorGetNum(); Vector vt = SK.GetEntity(g.predef.entityC)->VectorGetNum(); ut = ut.WithMagnitude(1); vt = vt.WithMagnitude(1); if(fabs(SS.GW.projUp.Dot(vt)) < fabs(SS.GW.projUp.Dot(ut))) { SWAP(Vector, ut, vt); g.predef.swapUV = true; } if(SS.GW.projRight.Dot(ut) < 0) g.predef.negateU = true; if(SS.GW.projUp. Dot(vt) < 0) g.predef.negateV = true; } else { Error("Bad selection for new sketch in workplane. This " "group can be created with:\n\n" " * a point (orthogonal to coordinate axes, " "through the point)\n" " * a point and two line segments (parallel to the " "lines, through the point)\n"); return; } break; case GraphicsWindow::MNU_GROUP_EXTRUDE: if(!SS.GW.LockedInWorkplane()) { Error("Select a workplane (Sketch -> In Workplane) before " "extruding. The sketch will be extruded normal to the " "workplane."); return; } g.type = EXTRUDE; g.opA = SS.GW.activeGroup; g.predef.entityB = SS.GW.ActiveWorkplane(); g.subtype = ONE_SIDED; g.name.strcpy("extrude"); break; case GraphicsWindow::MNU_GROUP_LATHE: if(gs.points == 1 && gs.vectors == 1 && gs.n == 2) { g.predef.origin = gs.point[0]; g.predef.entityB = gs.vector[0]; } else if(gs.lineSegments == 1 && gs.n == 1) { g.predef.origin = SK.GetEntity(gs.entity[0])->point[0]; g.predef.entityB = gs.entity[0]; // since a line segment is a vector } else { Error("Bad selection for new lathe group. This group can " "be created with:\n\n" " * a point and a line segment or normal " "(revolved about an axis parallel to line / " "normal, through point)\n" " * a line segment (revolved about line segment)\n"); return; } g.type = LATHE; g.opA = SS.GW.activeGroup; g.name.strcpy("lathe"); break; case GraphicsWindow::MNU_GROUP_ROT: { if(gs.points == 1 && gs.n == 1 && SS.GW.LockedInWorkplane()) { g.predef.origin = gs.point[0]; Entity *w = SK.GetEntity(SS.GW.ActiveWorkplane()); g.predef.entityB = w->Normal()->h; g.activeWorkplane = w->h; } else if(gs.points == 1 && gs.vectors == 1 && gs.n == 2) { g.predef.origin = gs.point[0]; g.predef.entityB = gs.vector[0]; } else { Error("Bad selection for new rotation. This group can " "be created with:\n\n" " * a point, while locked in workplane (rotate " "in plane, about that point)\n" " * a point and a line or a normal (rotate about " "an axis through the point, and parallel to " "line / normal)\n"); return; } g.type = ROTATE; g.opA = SS.GW.activeGroup; g.valA = 3; g.subtype = ONE_SIDED; g.name.strcpy("rotate"); break; } case GraphicsWindow::MNU_GROUP_TRANS: g.type = TRANSLATE; g.opA = SS.GW.activeGroup; g.valA = 3; g.subtype = ONE_SIDED; g.predef.entityB = SS.GW.ActiveWorkplane(); g.activeWorkplane = SS.GW.ActiveWorkplane(); g.name.strcpy("translate"); break; case GraphicsWindow::MNU_GROUP_IMPORT: { g.type = IMPORTED; g.opA = SS.GW.activeGroup; if(strlen(g.impFile) == 0) { if(!GetOpenFile(g.impFile, SLVS_EXT, SLVS_PATTERN)) return; } // Assign the default name of the group based on the name of // the imported file. char groupName[MAX_PATH]; strcpy(groupName, g.impFile); char *dot = strrchr(groupName, '.'); if(dot) *dot = '\0'; char *s, *start = groupName; for(s = groupName; *s; s++) { if(*s == '/' || *s == '\\') { start = s + 1; } else if(isalnum(*s)) { // do nothing, valid character } else { // convert invalid characters (like spaces) to dashes *s = '-'; } } if(strlen(start) > 0) { g.name.strcpy(start); } else { g.name.strcpy("import"); } g.meshCombine = COMBINE_AS_ASSEMBLE; break; } default: oops(); } SS.GW.ClearSelection(); SS.UndoRemember(); SK.group.AddAndAssignId(&g); Group *gg = SK.GetGroup(g.h); if(gg->type == IMPORTED) { SS.ReloadAllImported(); } gg->clean = false; SS.GW.activeGroup = gg->h; SS.GenerateAll(); if(gg->type == DRAWING_WORKPLANE) { // Can't set the active workplane for this one until after we've // regenerated, because the workplane doesn't exist until then. gg->activeWorkplane = gg->h.entity(0); } gg->Activate(); SS.GW.AnimateOntoWorkplane(); TextWindow::ScreenSelectGroup(0, gg->h.v); SS.later.showTW = true; }
void GraphicsWindow::MenuEdit(int id) { switch(id) { case MNU_UNSELECT_ALL: SS.GW.GroupSelection(); // If there's nothing selected to de-select, and no operation // to cancel, then perhaps they want to return to the home // screen in the text window. if(SS.GW.gs.n == 0 && SS.GW.gs.constraints == 0 && SS.GW.pending.operation == 0) { if(!(TextEditControlIsVisible() || GraphicsEditControlIsVisible())) { if(SS.TW.shown.screen == TextWindow::SCREEN_STYLE_INFO) { SS.TW.GoToScreen(TextWindow::SCREEN_LIST_OF_STYLES); } else { SS.TW.ClearSuper(); } } } SS.GW.ClearSuper(); SS.TW.HideEditControl(); SS.nakedEdges.Clear(); SS.justExportedInfo.draw = false; // This clears the marks drawn to indicate which points are // still free to drag. Param *p; for(p = SK.param.First(); p; p = SK.param.NextAfter(p)) { p->free = false; } if(SS.exportMode) { SS.exportMode = false; SS.GenerateAll(SolveSpaceUI::GENERATE_ALL); } break; case MNU_SELECT_ALL: { Entity *e; for(e = SK.entity.First(); e; e = SK.entity.NextAfter(e)) { if(e->group.v != SS.GW.activeGroup.v) continue; if(e->IsFace() || e->IsDistance()) continue; if(!e->IsVisible()) continue; SS.GW.MakeSelected(e->h); } InvalidateGraphics(); SS.ScheduleShowTW(); break; } case MNU_SELECT_CHAIN: { Entity *e; int newlySelected = 0; bool didSomething; do { didSomething = false; for(e = SK.entity.First(); e; e = SK.entity.NextAfter(e)) { if(e->group.v != SS.GW.activeGroup.v) continue; if(!e->HasEndpoints()) continue; if(!e->IsVisible()) continue; Vector st = e->EndpointStart(), fi = e->EndpointFinish(); bool onChain = false, alreadySelected = false; List<Selection> *ls = &(SS.GW.selection); for(Selection *s = ls->First(); s; s = ls->NextAfter(s)) { if(!s->entity.v) continue; if(s->entity.v == e->h.v) { alreadySelected = true; continue; } Entity *se = SK.GetEntity(s->entity); if(!se->HasEndpoints()) continue; Vector sst = se->EndpointStart(), sfi = se->EndpointFinish(); if(sst.Equals(st) || sst.Equals(fi) || sfi.Equals(st) || sfi.Equals(fi)) { onChain = true; } } if(onChain && !alreadySelected) { SS.GW.MakeSelected(e->h); newlySelected++; didSomething = true; } } } while(didSomething); if(newlySelected == 0) { Error("No additional entities share endpoints with the " "selected entities."); } InvalidateGraphics(); SS.ScheduleShowTW(); break; } case MNU_ROTATE_90: { SS.GW.GroupSelection(); Entity *e = NULL; if(SS.GW.gs.n == 1 && SS.GW.gs.points == 1) { e = SK.GetEntity(SS.GW.gs.point[0]); } else if(SS.GW.gs.n == 1 && SS.GW.gs.entities == 1) { e = SK.GetEntity(SS.GW.gs.entity[0]); } SS.GW.ClearSelection(); hGroup hg = e ? e->group : SS.GW.activeGroup; Group *g = SK.GetGroup(hg); if(g->type != Group::IMPORTED) { Error("To use this command, select a point or other " "entity from an imported part, or make an import " "group the active group."); break; } SS.UndoRemember(); // Rotate by ninety degrees about the coordinate axis closest // to the screen normal. Vector norm = SS.GW.projRight.Cross(SS.GW.projUp); norm = norm.ClosestOrtho(); norm = norm.WithMagnitude(1); Quaternion qaa = Quaternion::From(norm, PI/2); g->TransformImportedBy(Vector::From(0, 0, 0), qaa); // and regenerate as necessary. SS.MarkGroupDirty(hg); SS.GenerateAll(); break; } case MNU_SNAP_TO_GRID: { if(!SS.GW.LockedInWorkplane()) { Error("No workplane is active. Select a workplane to define " "the plane for the snap grid."); break; } SS.GW.GroupSelection(); if(SS.GW.gs.points == 0 && SS.GW.gs.constraintLabels == 0) { Error("Can't snap these items to grid; select points, " "text comments, or constraints with a label. " "To snap a line, select its endpoints."); break; } SS.UndoRemember(); List<Selection> *ls = &(SS.GW.selection); for(Selection *s = ls->First(); s; s = ls->NextAfter(s)) { if(s->entity.v) { hEntity hp = s->entity; Entity *ep = SK.GetEntity(hp); if(!ep->IsPoint()) continue; Vector p = ep->PointGetNum(); ep->PointForceTo(SS.GW.SnapToGrid(p)); SS.GW.pending.points.Add(&hp); SS.MarkGroupDirty(ep->group); } else if(s->constraint.v) { Constraint *c = SK.GetConstraint(s->constraint); c->disp.offset = SS.GW.SnapToGrid(c->disp.offset); } } // Regenerate, with these points marked as dragged so that they // get placed as close as possible to our snap grid. SS.GenerateAll(); SS.GW.ClearPending(); SS.GW.ClearSelection(); InvalidateGraphics(); break; } case MNU_UNDO: SS.UndoUndo(); break; case MNU_REDO: SS.UndoRedo(); break; case MNU_REGEN_ALL: SS.ReloadAllImported(); SS.GenerateAll(SolveSpaceUI::GENERATE_UNTIL_ACTIVE); SS.ScheduleShowTW(); break; default: oops(); } }