//----------------------------------------------------------------------------- // Select everything that lies within the marquee view-aligned rectangle. For // points, we test by the point location. For normals, we test by the normal's // associated point. For anything else, we test by any piecewise linear edge. //----------------------------------------------------------------------------- void GraphicsWindow::SelectByMarquee(void) { Point2d begin = ProjectPoint(orig.marqueePoint); double xmin = min(orig.mouse.x, begin.x), xmax = max(orig.mouse.x, begin.x), ymin = min(orig.mouse.y, begin.y), ymax = max(orig.mouse.y, begin.y); 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; if(e->IsPoint() || e->IsNormal()) { Vector p = e->IsPoint() ? e->PointGetNum() : SK.GetEntity(e->point[0])->PointGetNum(); Point2d pp = ProjectPoint(p); if(pp.x >= xmin && pp.x <= xmax && pp.y >= ymin && pp.y <= ymax) { MakeSelected(e->h); } } else { // Use the 3d bounding box test routines, to avoid duplication; // so let our bounding square become a bounding box that certainly // includes the z = 0 plane. Vector ptMin = Vector::From(xmin, ymin, -1), ptMax = Vector::From(xmax, ymax, 1); SEdgeList sel; ZERO(&sel); e->GenerateEdges(&sel, true); SEdge *se; for(se = sel.l.First(); se; se = sel.l.NextAfter(se)) { Point2d ppa = ProjectPoint(se->a), ppb = ProjectPoint(se->b); Vector ptA = Vector::From(ppa.x, ppa.y, 0), ptB = Vector::From(ppb.x, ppb.y, 0); if(Vector::BoundingBoxIntersectsLine(ptMax, ptMin, ptA, ptB, true) || !ptA.OutsideAndNotOn(ptMax, ptMin) || !ptB.OutsideAndNotOn(ptMax, ptMin)) { MakeSelected(e->h); break; } } sel.Clear(); } } }
void AbstractFeatureMatcher::ReconsiderOldPoints(const std::shared_ptr<Core::PointOfView> &pointOfView, std::vector<Core::Projection> detectedFeatures) { if (!pointOfView->GetCameraParameters().IsPoseDetermined()) { return; } std::vector<Core::Projection> projectionsInCurrentView; for (auto it = scene->GetFeatures()->Begin(); it != scene->GetFeatures()->End(); ++it) { Core::Projection projection = it->ProjectPoint(pointOfView); if (projection.GetX() < 0 || projection.GetY() < 0 || projection.GetX() > pointOfView->GetImage()->GetSize().width || projection.GetY() > pointOfView->GetImage()->GetSize().height) { continue; } projectionsInCurrentView.push_back(projection); } for (const Core::Projection &projection : projectionsInCurrentView) { for (const Core::Projection &actualFeature : detectedFeatures) { } } // project all points to this POV // see which ones are inside the image // use them and try matching against detected keypoints }
Rect Matrix4x4::ProjectRectBounds(const Rect& aRect) const { Point4D points[4]; points[0] = ProjectPoint(aRect.TopLeft()); points[1] = ProjectPoint(aRect.TopRight()); points[2] = ProjectPoint(aRect.BottomRight()); points[3] = ProjectPoint(aRect.BottomLeft()); Float min_x = std::numeric_limits<Float>::max(); Float min_y = std::numeric_limits<Float>::max(); Float max_x = -std::numeric_limits<Float>::max(); Float max_y = -std::numeric_limits<Float>::max(); bool foundPoint = false; for (int i=0; i<4; i++) { // Only use points that exist above the w=0 plane if (points[i].HasPositiveWCoord()) { foundPoint = true; Point point2d = points[i].As2DPoint(); min_x = min<Float>(point2d.x, min_x); max_x = max<Float>(point2d.x, max_x); min_y = min<Float>(point2d.y, min_y); max_y = max<Float>(point2d.y, max_y); } int next = (i == 3) ? 0 : i + 1; if (points[i].HasPositiveWCoord() != points[next].HasPositiveWCoord()) { // If the line between two points crosses the w=0 plane, then interpolate a point // as close to the w=0 plane as possible and use that instead. Point4D intercept = ComputePerspectivePlaneIntercept(points[i], points[next]); Point point2d = intercept.As2DPoint(); min_x = min<Float>(point2d.x, min_x); max_x = max<Float>(point2d.x, max_x); min_y = min<Float>(point2d.y, min_y); max_y = max<Float>(point2d.y, max_y); } } if (!foundPoint) { return Rect(0, 0, 0, 0); } return Rect(min_x, min_y, max_x - min_x, max_y - min_y); }
void CCadEdge2DPolyline::SetCadEdge(const Cad::CCadObj2D& cad_2d, const unsigned int id_e, const Com::CVector2D& pick_pos) { this->pick_pos = pick_pos; this->m_IdECad = id_e; this->ClearMemory(); std::vector<double> aRelCoPoly; { assert( cad_2d.IsElemID(Cad::EDGE,id_e) ); const Cad::CEdge2D& e = cad_2d.GetEdge(id_e); aRelCoPoly = e.GetCurveRelPoint(); } std::vector<double> aXYs; const unsigned int ndiv = aRelCoPoly.size()/2+1; nno = ndiv+1; aXYs.reserve(nno*2); unsigned int id_vs = cad_2d.GetIdVertex_Edge(id_e,true ); unsigned int id_ve = cad_2d.GetIdVertex_Edge(id_e,false); const Com::CVector2D& vs = cad_2d.GetVertexCoord(id_vs); const Com::CVector2D& ve = cad_2d.GetVertexCoord(id_ve); const Com::CVector2D hse = ve-vs; const Com::CVector2D vse = Com::CVector2D(-hse.y,hse.x); aXYs.push_back(vs.x); aXYs.push_back(vs.y); for(unsigned int i=0;i<ndiv-1;i++){ Com::CVector2D v = vs+aRelCoPoly[i*2+0]*hse+aRelCoPoly[i*2+1]*vse; aXYs.push_back(v.x); aXYs.push_back(v.y); } aXYs.push_back(ve.x); aXYs.push_back(ve.y); ////////////////////////////////////// this->m_mat = new CTriDiaMat3(nno); ini_x = new double [nno*2]; ut = new double [nno*3]; Res = new double [nno*3]; dut = new double [nno*3]; bc_flag = new int [nno*3]; //// for(unsigned int i=0;i<nno*2;i++){ ini_x[i] = aXYs[i]; } for(unsigned int i=0;i<nno*3;i++){ ut[i] = 0; } for(unsigned int i=0;i<nno*3;i++){ bc_flag[i] = 0; } ////////////////////////////////////// this->SetFixedBoundaryFlag(0,0); this->SetFixedBoundaryFlag(0,1); this->SetFixedBoundaryFlag(nno-1,0); this->SetFixedBoundaryFlag(nno-1,1); double alpha, ndist, norm_x, norm_y; ProjectPoint(pick_pos.x, pick_pos.y, idiv_picked, alpha, ndist, norm_x, norm_y); if( idiv_picked == -1 ) return; this->SetFixedBoundaryFlag(idiv_picked,0); this->SetFixedBoundaryFlag(idiv_picked,1); this->SetFixedBoundaryFlag(idiv_picked+1,0); this->SetFixedBoundaryFlag(idiv_picked+1,1); }
int MeshOptimize2dOCCSurfaces :: ProjectPointGI (INDEX surfind, Point<3> & p, PointGeomInfo & gi) const { double u = gi.u; double v = gi.v; Point<3> hp = p; if (geometry.FastProject (surfind, hp, u, v)) { p = hp; return 1; } ProjectPoint (surfind, p); return CalcPointGeomInfo (surfind, gi, p); }
void MeshOptimize2d :: ProjectBoundaryPoints(Array<int> & surfaceindex, const Array<Point<3>* > & from, Array<Point<3>* > & dest) { for(int i=0; i<surfaceindex.Size(); i++) { if(surfaceindex[i] >= 0) { *dest[i] = *from[i]; ProjectPoint(surfaceindex[i],*dest[i]); } } }
void GPSView::AddGPSPoints(GPSPoints &p){ int width; int height; GetClientSize(&width, &height); Point minXY(-1, -1); Point maxXY(-1, -1); for (size_t i = 0; i < p.Count(); i++){ Point point = ProjectPoint(p[i]); minXY.x = ((minXY.x == -1) ? point.x : std::min(minXY.x, point.x)); minXY.y = ((minXY.y == -1) ? point.y : std::min(minXY.y, point.y)); m_trackPoints.Add(point); } for (size_t i = 0; i < m_trackPoints.size(); i++){ Point point = m_trackPoints[i]; point.x = point.x - minXY.x; point.y = point.y - minXY.y; // now, we need to keep track the max X and Y values maxXY.x = (maxXY.x == -1) ? point.x : std::max(maxXY.x, point.x); maxXY.y = (maxXY.y == -1) ? point.y : std::max(maxXY.y, point.y); } int paddingBothSides = MIN_PADDING * 2; // the actual drawing space for the map on the image int mapWidth = width - paddingBothSides; int mapHeight = height - paddingBothSides; // determine the width and height ratio because we need to magnify the map to fit into the given image dimension double mapWidthRatio = mapWidth / maxXY.x; double mapHeightRatio = mapHeight / maxXY.y; // using different ratios for width and height will cause the map to be stretched. So, we have to determine // the global ratio that will perfectly fit into the given image dimension m_globalRatio = std::min(mapWidthRatio, mapHeightRatio); // now we need to readjust the padding to ensure the map is always drawn on the center of the given image dimension m_heightPadding = (height - (m_globalRatio * maxXY.y)) / 2; m_widthPadding = (width - (m_globalRatio * maxXY.x)) / 2; m_offsetPoint = minXY; UpdateMinMax(m_trackPoints); RefreshBackground(); }
BLORTSubRect BLORTObjectsManager::GetSubRect(int object_size) { BLORTSubRect res; int minX = camPar.width; int maxX = 0; int minY = camPar.height; int maxY = 0; for(std::map<std::string, TomGine::tgPose>::iterator it = positions.begin(); it != positions.end(); ++it) { int u = 0; int v = 0; ProjectPoint(it->second, u, v); if(u < minX) { minX = u; } if(u > maxX) { maxX = u; } if(v < minY) { minY = v; } if(v > maxY) { maxY = v; } } minX = minX > object_size/2 ? minX - object_size/2 : 0; maxX = maxX + object_size/2 > camPar.height - 1 ? camPar.height - 1 : maxX + object_size/2; minY = minY > object_size/2 ? minY - object_size/2 : 0; maxY = maxY + object_size/2 > camPar.height - 1 ? camPar.height - 1 : maxY + object_size/2; res.left = minX; res.top = minY; res.width = maxX - minX; res.height = maxY - minY; /* Preserve aspect ratio */ if(res.width > res.height) { int heightDiff = (double)camPar.height/(double)camPar.width * res.width - res.height; res.height += heightDiff; res.top -= heightDiff/2; res.top = res.top < 0 ? 0 : res.top; } else { int widthDiff = (double)camPar.width/(double)camPar.height * res.height - res.width; res.width += widthDiff; res.left -= widthDiff/2; res.left = res.left < 0 ? 0 : res.left; } return res; }
Rect Matrix4x4::ProjectRectBounds(const Rect& aRect, const Rect &aClip) const { // This function must never return std::numeric_limits<Float>::max() or any // other arbitrary large value in place of inifinity. This often occurs when // aRect is an inversed projection matrix or when aRect is transformed to be // partly behind and in front of the camera (w=0 plane in homogenous // coordinates) - See Bug 1035611 // Some call-sites will call RoundGfxRectToAppRect which clips both the // extents and dimensions of the rect to be bounded by nscoord_MAX. // If we return a Rect that, when converted to nscoords, has a width or height // greater than nscoord_MAX, RoundGfxRectToAppRect will clip the overflow // off both the min and max end of the rect after clipping the extents of the // rect, resulting in a translation of the rect towards the infinite end. // The bounds returned by ProjectRectBounds are expected to be clipped only on // the edges beyond the bounds of the coordinate system; otherwise, the // clipped bounding box would be smaller than the correct one and result // bugs such as incorrect culling (eg. Bug 1073056) // To address this without requiring all code to work in homogenous // coordinates or interpret infinite values correctly, a specialized // clipping function is integrated into ProjectRectBounds. // Callers should pass an aClip value that represents the extents to clip // the result to, in the same coordinate system as aRect. Point4D points[4]; points[0] = ProjectPoint(aRect.TopLeft()); points[1] = ProjectPoint(aRect.TopRight()); points[2] = ProjectPoint(aRect.BottomRight()); points[3] = ProjectPoint(aRect.BottomLeft()); Float min_x = std::numeric_limits<Float>::max(); Float min_y = std::numeric_limits<Float>::max(); Float max_x = -std::numeric_limits<Float>::max(); Float max_y = -std::numeric_limits<Float>::max(); for (int i=0; i<4; i++) { // Only use points that exist above the w=0 plane if (points[i].HasPositiveWCoord()) { Point point2d = aClip.ClampPoint(points[i].As2DPoint()); min_x = std::min<Float>(point2d.x, min_x); max_x = std::max<Float>(point2d.x, max_x); min_y = std::min<Float>(point2d.y, min_y); max_y = std::max<Float>(point2d.y, max_y); } int next = (i == 3) ? 0 : i + 1; if (points[i].HasPositiveWCoord() != points[next].HasPositiveWCoord()) { // If the line between two points crosses the w=0 plane, then interpolate // to find the point of intersection with the w=0 plane and use that // instead. Point4D intercept = ComputePerspectivePlaneIntercept(points[i], points[next]); // Since intercept.w will always be 0 here, we interpret x,y,z as a // direction towards an infinite vanishing point. if (intercept.x < 0.0f) { min_x = aClip.x; } else if (intercept.x > 0.0f) { max_x = aClip.XMost(); } if (intercept.y < 0.0f) { min_y = aClip.y; } else if (intercept.y > 0.0f) { max_y = aClip.YMost(); } } } if (max_x < min_x || max_y < min_y) { return Rect(0, 0, 0, 0); } return Rect(min_x, min_y, max_x - min_x, max_y - min_y); }
void GraphicsWindow::SplitLinesOrCurves(void) { if(!LockedInWorkplane()) { Error("Must be sketching in workplane to split."); return; } GroupSelection(); if(!(gs.n == 2 &&(gs.lineSegments + gs.circlesOrArcs + gs.cubics + gs.periodicCubics) == 2)) { Error("Select two entities that intersect each other (e.g. two lines " "or two circles or a circle and a line)."); return; } hEntity ha = gs.entity[0], hb = gs.entity[1]; Entity *ea = SK.GetEntity(ha), *eb = SK.GetEntity(hb); // Compute the possibly-rational Bezier curves for each of these entities SBezierList sbla, sblb; ZERO(&sbla); ZERO(&sblb); ea->GenerateBezierCurves(&sbla); eb->GenerateBezierCurves(&sblb); // and then compute the points where they intersect, based on those curves. SPointList inters; ZERO(&inters); sbla.AllIntersectionsWith(&sblb, &inters); if(inters.l.n > 0) { Vector pi; // If there's multiple points, then take the one closest to the // mouse pointer. double dmin = VERY_POSITIVE; SPoint *sp; for(sp = inters.l.First(); sp; sp = inters.l.NextAfter(sp)) { double d = ProjectPoint(sp->p).DistanceTo(currentMousePosition); if(d < dmin) { dmin = d; pi = sp->p; } } SS.UndoRemember(); hEntity hia = SplitEntity(ha, pi), hib = SplitEntity(hb, pi); // SplitEntity adds the coincident constraints to join the split halves // of each original entity; and then we add the constraint to join // the two entities together at the split point. if(hia.v && hib.v) { Constraint::ConstrainCoincident(hia, hib); } } else { Error("Can't split; no intersection found."); } // All done, clean up and regenerate. inters.Clear(); sbla.Clear(); sblb.Clear(); ClearSelection(); SS.later.generateAll = true; }
/// project point, use gi as initial value, and compute new gi virtual int ProjectPointGI (INDEX surfind, Point<3> & p, PointGeomInfo & gi) const { ProjectPoint (surfind, p); return CalcPointGeomInfo (surfind, gi, p); }
void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown) { if(GraphicsEditControlIsVisible()) return; if(context.active) return; SS.extraLine.draw = false; if(!orig.mouseDown) { // If someone drags the mouse into our window with the left button // already depressed, then we don't have our starting point; so // don't try. leftDown = false; } if(rightDown) { middleDown = true; shiftDown = !shiftDown; } if(SS.showToolbar) { if(ToolbarMouseMoved((int)x, (int)y)) { hover.Clear(); return; } } if(!leftDown && (pending.operation == DRAGGING_POINTS || pending.operation == DRAGGING_MARQUEE)) { ClearPending(); InvalidateGraphics(); } Point2d mp = Point2d::From(x, y); currentMousePosition = mp; if(rightDown && orig.mouse.DistanceTo(mp) < 5 && !orig.startedMoving) { // Avoid accidentally panning (or rotating if shift is down) if the // user wants a context menu. return; } orig.startedMoving = true; // If the middle button is down, then mouse movement is used to pan and // rotate our view. This wins over everything else. if(middleDown) { hover.Clear(); double dx = (x - orig.mouse.x) / scale; double dy = (y - orig.mouse.y) / scale; if(!(shiftDown || ctrlDown)) { double s = 0.3*(PI/180)*scale; // degrees per pixel projRight = orig.projRight.RotatedAbout(orig.projUp, -s*dx); projUp = orig.projUp.RotatedAbout(orig.projRight, s*dy); NormalizeProjectionVectors(); } else if(ctrlDown) { double theta = atan2(orig.mouse.y, orig.mouse.x); theta -= atan2(y, x); SS.extraLine.draw = true; SS.extraLine.ptA = UnProjectPoint(Point2d::From(0, 0)); SS.extraLine.ptB = UnProjectPoint(mp); Vector normal = orig.projRight.Cross(orig.projUp); projRight = orig.projRight.RotatedAbout(normal, theta); projUp = orig.projUp.RotatedAbout(normal, theta); NormalizeProjectionVectors(); } else { offset.x = orig.offset.x + dx*projRight.x + dy*projUp.x; offset.y = orig.offset.y + dx*projRight.y + dy*projUp.y; offset.z = orig.offset.z + dx*projRight.z + dy*projUp.z; } orig.projRight = projRight; orig.projUp = projUp; orig.offset = offset; orig.mouse.x = x; orig.mouse.y = y; if(SS.TW.shown.screen == TextWindow::SCREEN_EDIT_VIEW) { if(havePainted) { SS.ScheduleShowTW(); } } InvalidateGraphics(); havePainted = false; return; } if(pending.operation == 0) { double dm = orig.mouse.DistanceTo(mp); // If we're currently not doing anything, then see if we should // start dragging something. if(leftDown && dm > 3) { Entity *e = NULL; if(hover.entity.v) e = SK.GetEntity(hover.entity); if(e && e->type != Entity::WORKPLANE) { Entity *e = SK.GetEntity(hover.entity); if(e->type == Entity::CIRCLE && selection.n <= 1) { // Drag the radius. ClearSelection(); pending.circle = hover.entity; pending.operation = DRAGGING_RADIUS; } else if(e->IsNormal()) { ClearSelection(); pending.normal = hover.entity; pending.operation = DRAGGING_NORMAL; } else { if(!hoverWasSelectedOnMousedown) { // The user clicked an unselected entity, which // means they're dragging just the hovered thing, // not the full selection. So clear all the selection // except that entity. ClearSelection(); MakeSelected(e->h); } StartDraggingBySelection(); if(!hoverWasSelectedOnMousedown) { // And then clear the selection again, since they // probably didn't want that selected if they just // were dragging it. ClearSelection(); } hover.Clear(); pending.operation = DRAGGING_POINTS; } } else if(hover.constraint.v && SK.GetConstraint(hover.constraint)->HasLabel()) { ClearSelection(); pending.constraint = hover.constraint; pending.operation = DRAGGING_CONSTRAINT; } if(pending.operation != 0) { // We just started a drag, so remember for the undo before // the drag changes anything. SS.UndoRemember(); } else { if(!hover.constraint.v) { // That's just marquee selection, which should not cause // an undo remember. if(dm > 10) { if(hover.entity.v) { // Avoid accidentally selecting workplanes when // starting drags. MakeUnselected(hover.entity, false); hover.Clear(); } pending.operation = DRAGGING_MARQUEE; orig.marqueePoint = UnProjectPoint(orig.mouseOnButtonDown); } } } } else { // Otherwise, just hit test and give up; but don't hit test // if the mouse is down, because then the user could hover // a point, mouse down (thus selecting it), and drag, in an // effort to drag the point, but instead hover a different // entity before we move far enough to start the drag. if(!leftDown) HitTestMakeSelection(mp); } return; } // If the user has started an operation from the menu, but not // completed it, then just do the selection. if(pending.operation < FIRST_PENDING) { HitTestMakeSelection(mp); return; } // We're currently dragging something; so do that. But if we haven't // painted since the last time we solved, do nothing, because there's // no sense solving a frame and not displaying it. if(!havePainted) { if(pending.operation == DRAGGING_POINTS && ctrlDown) { SS.extraLine.ptA = UnProjectPoint(orig.mouseOnButtonDown); SS.extraLine.ptB = UnProjectPoint(mp); SS.extraLine.draw = true; } return; } switch(pending.operation) { case DRAGGING_CONSTRAINT: { Constraint *c = SK.constraint.FindById(pending.constraint); UpdateDraggedNum(&(c->disp.offset), x, y); orig.mouse = mp; InvalidateGraphics(); break; } case DRAGGING_NEW_LINE_POINT: case DRAGGING_NEW_POINT: UpdateDraggedPoint(pending.point, x, y); HitTestMakeSelection(mp); SS.MarkGroupDirtyByEntity(pending.point); orig.mouse = mp; InvalidateGraphics(); break; case DRAGGING_POINTS: if(shiftDown || ctrlDown) { // Edit the rotation associated with a POINT_N_ROT_TRANS, // either within (ctrlDown) or out of (shiftDown) the plane // of the screen. So first get the rotation to apply, in qt. Quaternion qt; if(ctrlDown) { double d = mp.DistanceTo(orig.mouseOnButtonDown); if(d < 25) { // Don't start dragging the position about the normal // until we're a little ways out, to get a reasonable // reference pos orig.mouse = mp; break; } double theta = atan2(orig.mouse.y-orig.mouseOnButtonDown.y, orig.mouse.x-orig.mouseOnButtonDown.x); theta -= atan2(y-orig.mouseOnButtonDown.y, x-orig.mouseOnButtonDown.x); Vector gn = projRight.Cross(projUp); qt = Quaternion::From(gn, -theta); SS.extraLine.draw = true; SS.extraLine.ptA = UnProjectPoint(orig.mouseOnButtonDown); SS.extraLine.ptB = UnProjectPoint(mp); } else { double dx = -(x - orig.mouse.x); double dy = -(y - orig.mouse.y); double s = 0.3*(PI/180); // degrees per pixel qt = Quaternion::From(projUp, -s*dx).Times( Quaternion::From(projRight, s*dy)); } orig.mouse = mp; // Now apply this rotation to the points being dragged. List<hEntity> *lhe = &(pending.points); for(hEntity *he = lhe->First(); he; he = lhe->NextAfter(he)) { Entity *e = SK.GetEntity(*he); if(e->type != Entity::POINT_N_ROT_TRANS) { if(ctrlDown) { Vector p = e->PointGetNum(); p = p.Minus(SS.extraLine.ptA); p = qt.Rotate(p); p = p.Plus(SS.extraLine.ptA); e->PointForceTo(p); SS.MarkGroupDirtyByEntity(e->h); } continue; } Quaternion q = e->PointGetQuaternion(); Vector p = e->PointGetNum(); q = qt.Times(q); e->PointForceQuaternionTo(q); // Let's rotate about the selected point; so fix up the // translation so that that point didn't move. e->PointForceTo(p); SS.MarkGroupDirtyByEntity(e->h); } } else { List<hEntity> *lhe = &(pending.points); for(hEntity *he = lhe->First(); he; he = lhe->NextAfter(he)) { UpdateDraggedPoint(*he, x, y); SS.MarkGroupDirtyByEntity(*he); } orig.mouse = mp; } break; case DRAGGING_NEW_CUBIC_POINT: { UpdateDraggedPoint(pending.point, x, y); HitTestMakeSelection(mp); hRequest hr = pending.point.request(); if(pending.point.v == hr.entity(4).v) { // The very first segment; dragging final point drags both // tangent points. Vector p0 = SK.GetEntity(hr.entity(1))->PointGetNum(), p3 = SK.GetEntity(hr.entity(4))->PointGetNum(), p1 = p0.ScaledBy(2.0/3).Plus(p3.ScaledBy(1.0/3)), p2 = p0.ScaledBy(1.0/3).Plus(p3.ScaledBy(2.0/3)); SK.GetEntity(hr.entity(1+1))->PointForceTo(p1); SK.GetEntity(hr.entity(1+2))->PointForceTo(p2); } else { // A subsequent segment; dragging point drags only final // tangent point. int i = SK.GetEntity(hr.entity(0))->extraPoints; Vector pn = SK.GetEntity(hr.entity(4+i))->PointGetNum(), pnm2 = SK.GetEntity(hr.entity(2+i))->PointGetNum(), pnm1 = (pn.Plus(pnm2)).ScaledBy(0.5); SK.GetEntity(hr.entity(3+i))->PointForceTo(pnm1); } orig.mouse = mp; SS.MarkGroupDirtyByEntity(pending.point); break; } case DRAGGING_NEW_ARC_POINT: { UpdateDraggedPoint(pending.point, x, y); HitTestMakeSelection(mp); hRequest hr = pending.point.request(); Vector ona = SK.GetEntity(hr.entity(2))->PointGetNum(); Vector onb = SK.GetEntity(hr.entity(3))->PointGetNum(); Vector center = (ona.Plus(onb)).ScaledBy(0.5); SK.GetEntity(hr.entity(1))->PointForceTo(center); orig.mouse = mp; SS.MarkGroupDirtyByEntity(pending.point); break; } case DRAGGING_NEW_RADIUS: case DRAGGING_RADIUS: { Entity *circle = SK.GetEntity(pending.circle); Vector center = SK.GetEntity(circle->point[0])->PointGetNum(); Point2d c2 = ProjectPoint(center); double r = c2.DistanceTo(mp)/scale; SK.GetEntity(circle->distance)->DistanceForceTo(r); SS.MarkGroupDirtyByEntity(pending.circle); break; } case DRAGGING_NORMAL: { Entity *normal = SK.GetEntity(pending.normal); Vector p = SK.GetEntity(normal->point[0])->PointGetNum(); Point2d p2 = ProjectPoint(p); Quaternion q = normal->NormalGetNum(); Vector u = q.RotationU(), v = q.RotationV(); if(ctrlDown) { double theta = atan2(orig.mouse.y-p2.y, orig.mouse.x-p2.x); theta -= atan2(y-p2.y, x-p2.x); Vector normal = projRight.Cross(projUp); u = u.RotatedAbout(normal, -theta); v = v.RotatedAbout(normal, -theta); } else { double dx = -(x - orig.mouse.x); double dy = -(y - orig.mouse.y); double s = 0.3*(PI/180); // degrees per pixel u = u.RotatedAbout(projUp, -s*dx); u = u.RotatedAbout(projRight, s*dy); v = v.RotatedAbout(projUp, -s*dx); v = v.RotatedAbout(projRight, s*dy); } orig.mouse = mp; normal->NormalForceTo(Quaternion::From(u, v)); SS.MarkGroupDirtyByEntity(pending.normal); break; } case DRAGGING_MARQUEE: orig.mouse = mp; InvalidateGraphics(); break; default: oops(); } if(pending.operation != 0 && pending.operation != DRAGGING_CONSTRAINT && pending.operation != DRAGGING_MARQUEE) { SS.GenerateAll(); } havePainted = false; }
void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) { if(GraphicsEditControlIsVisible()) return; SS.TW.HideEditControl(); if(hover.constraint.v) { constraintBeingEdited = hover.constraint; ClearSuper(); Constraint *c = SK.GetConstraint(constraintBeingEdited); if(!c->HasLabel()) { // Not meaningful to edit a constraint without a dimension return; } if(c->reference) { // Not meaningful to edit a reference dimension return; } Vector p3 = c->GetLabelPos(); Point2d p2 = ProjectPoint(p3); char s[1024]; switch(c->type) { case Constraint::COMMENT: strcpy(s, c->comment.str); break; case Constraint::ANGLE: case Constraint::LENGTH_RATIO: sprintf(s, "%.3f", c->valA); break; default: { double v = fabs(c->valA); // If displayed as radius, also edit as radius. if(c->type == Constraint::DIAMETER && c->disp.toggleA) v /= 2; char *def = SS.MmToString(v); double eps = 1e-12; if(fabs(SS.StringToMm(def) - v) < eps) { // Show value with default number of digits after decimal, // which is at least enough to represent it exactly. strcpy(s, def); } else { // Show value with as many digits after decimal as // required to represent it exactly, up to 10. v /= SS.MmPerUnit(); int i; for(i = 0; i <= 10; i++) { sprintf(s, "%.*f", i, v); if(fabs(atof(s) - v) < eps) break; } } break; } } ShowGraphicsEditControl((int)p2.x, (int)p2.y-4, s); } }
void GPSView::SetMarker(GPSPoint &p) { m_marker = ProjectPoint(p); Refresh(); }
void GraphicsWindow::Paint(void) { int i; havePainted = true; int w, h; GetGraphicsWindowSize(&w, &h); width = w; height = h; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glScaled(scale*2.0/w, scale*2.0/h, scale*1.0/30000); double mat[16]; // Last thing before display is to apply the perspective double clp = SS.CameraTangent()*scale; MakeMatrix(mat, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, clp, 1); glMultMatrixd(mat); // Before that, we apply the rotation Vector n = projUp.Cross(projRight); MakeMatrix(mat, projRight.x, projRight.y, projRight.z, 0, projUp.x, projUp.y, projUp.z, 0, n.x, n.y, n.z, 0, 0, 0, 0, 1); glMultMatrixd(mat); // And before that, the translation MakeMatrix(mat, 1, 0, 0, offset.x, 0, 1, 0, offset.y, 0, 0, 1, offset.z, 0, 0, 0, 1); glMultMatrixd(mat); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glShadeModel(GL_SMOOTH); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); // don't enable GL_POLYGON_SMOOTH; that looks ugly on some graphics cards, // drawn with leaks in the mesh glEnable(GL_POLYGON_OFFSET_LINE); glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_DEPTH_TEST); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glEnable(GL_NORMALIZE); // At the same depth, we want later lines drawn over earlier. glDepthFunc(GL_LEQUAL); if(SS.AllGroupsOkay()) { glClearColor(SS.backgroundColor.redF(), SS.backgroundColor.greenF(), SS.backgroundColor.blueF(), 1.0f); } else { // Draw a different background whenever we're having solve problems. RgbColor rgb = Style::Color(Style::DRAW_ERROR); glClearColor(0.4f*rgb.redF(), 0.4f*rgb.greenF(), 0.4f*rgb.blueF(), 1.0f); // And show the text window, which has info to debug it ForceTextWindowShown(); } glClear(GL_COLOR_BUFFER_BIT); glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); if(SS.bgImage.fromFile) { // If a background image is loaded, then we draw it now as a texture. // This handles the resizing for us nicely. glBindTexture(GL_TEXTURE_2D, TEXTURE_BACKGROUND_IMG); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SS.bgImage.rw, SS.bgImage.rh, 0, GL_RGB, GL_UNSIGNED_BYTE, SS.bgImage.fromFile); double tw = ((double)SS.bgImage.w) / SS.bgImage.rw, th = ((double)SS.bgImage.h) / SS.bgImage.rh; double mmw = SS.bgImage.w / SS.bgImage.scale, mmh = SS.bgImage.h / SS.bgImage.scale; Vector origin = SS.bgImage.origin; origin = origin.DotInToCsys(projRight, projUp, n); // Place the depth of our origin at the point that corresponds to // w = 1, so that it's unaffected by perspective. origin.z = (offset.ScaledBy(-1)).Dot(n); origin = origin.ScaleOutOfCsys(projRight, projUp, n); // Place the background at the very back of the Z order, though, by // mucking with the depth range. glDepthRange(1, 1); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2d(0, 0); ssglVertex3v(origin); glTexCoord2d(0, th); ssglVertex3v(origin.Plus(projUp.ScaledBy(mmh))); glTexCoord2d(tw, th); ssglVertex3v(origin.Plus(projRight.ScaledBy(mmw).Plus( projUp. ScaledBy(mmh)))); glTexCoord2d(tw, 0); ssglVertex3v(origin.Plus(projRight.ScaledBy(mmw))); glEnd(); glDisable(GL_TEXTURE_2D); } ssglDepthRangeOffset(0); // Nasty case when we're reloading the imported files; could be that // we get an error, so a dialog pops up, and a message loop starts, and // we have to get called to paint ourselves. If the sketch is screwed // up, then we could trigger an oops trying to draw. if(!SS.allConsistent) return; // Let's use two lights, at the user-specified locations GLfloat f; glEnable(GL_LIGHT0); f = (GLfloat)SS.lightIntensity[0]; GLfloat li0[] = { f, f, f, 1.0f }; glLightfv(GL_LIGHT0, GL_DIFFUSE, li0); glLightfv(GL_LIGHT0, GL_SPECULAR, li0); glEnable(GL_LIGHT1); f = (GLfloat)SS.lightIntensity[1]; GLfloat li1[] = { f, f, f, 1.0f }; glLightfv(GL_LIGHT1, GL_DIFFUSE, li1); glLightfv(GL_LIGHT1, GL_SPECULAR, li1); Vector ld; ld = VectorFromProjs(SS.lightDir[0]); GLfloat ld0[4] = { (GLfloat)ld.x, (GLfloat)ld.y, (GLfloat)ld.z, 0 }; glLightfv(GL_LIGHT0, GL_POSITION, ld0); ld = VectorFromProjs(SS.lightDir[1]); GLfloat ld1[4] = { (GLfloat)ld.x, (GLfloat)ld.y, (GLfloat)ld.z, 0 }; glLightfv(GL_LIGHT1, GL_POSITION, ld1); if(SS.drawBackFaces) { // For debugging, draw the backs of the triangles in red, so that we // notice when a shell is open glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1); } else { glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 0); } GLfloat ambient[4] = { (float)SS.ambientIntensity, (float)SS.ambientIntensity, (float)SS.ambientIntensity, 1 }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); ssglUnlockColor(); if(showSnapGrid && LockedInWorkplane()) { hEntity he = ActiveWorkplane(); EntityBase *wrkpl = SK.GetEntity(he), *norm = wrkpl->Normal(); Vector wu, wv, wn, wp; wp = SK.GetEntity(wrkpl->point[0])->PointGetNum(); wu = norm->NormalU(); wv = norm->NormalV(); wn = norm->NormalN(); double g = SS.gridSpacing; double umin = VERY_POSITIVE, umax = VERY_NEGATIVE, vmin = VERY_POSITIVE, vmax = VERY_NEGATIVE; int a; for(a = 0; a < 4; a++) { // Ideally, we would just do +/- half the width and height; but // allow some extra slop for rounding. Vector horiz = projRight.ScaledBy((0.6*width)/scale + 2*g), vert = projUp. ScaledBy((0.6*height)/scale + 2*g); if(a == 2 || a == 3) horiz = horiz.ScaledBy(-1); if(a == 1 || a == 3) vert = vert. ScaledBy(-1); Vector tp = horiz.Plus(vert).Minus(offset); // Project the point into our grid plane, normal to the screen // (not to the grid plane). If the plane is on edge then this is // impossible so don't try to draw the grid. bool parallel; Vector tpp = Vector::AtIntersectionOfPlaneAndLine( wn, wn.Dot(wp), tp, tp.Plus(n), ¶llel); if(parallel) goto nogrid; tpp = tpp.Minus(wp); double uu = tpp.Dot(wu), vv = tpp.Dot(wv); umin = min(uu, umin); umax = max(uu, umax); vmin = min(vv, vmin); vmax = max(vv, vmax); } int i, j, i0, i1, j0, j1; i0 = (int)(umin / g); i1 = (int)(umax / g); j0 = (int)(vmin / g); j1 = (int)(vmax / g); if(i0 > i1 || i1 - i0 > 400) goto nogrid; if(j0 > j1 || j1 - j0 > 400) goto nogrid; glLineWidth(1); ssglColorRGBa(Style::Color(Style::DATUM), 0.3); glBegin(GL_LINES); for(i = i0 + 1; i < i1; i++) { ssglVertex3v(wp.Plus(wu.ScaledBy(i*g)).Plus(wv.ScaledBy(j0*g))); ssglVertex3v(wp.Plus(wu.ScaledBy(i*g)).Plus(wv.ScaledBy(j1*g))); } for(j = j0 + 1; j < j1; j++) { ssglVertex3v(wp.Plus(wu.ScaledBy(i0*g)).Plus(wv.ScaledBy(j*g))); ssglVertex3v(wp.Plus(wu.ScaledBy(i1*g)).Plus(wv.ScaledBy(j*g))); } glEnd(); // Clear the depth buffer, so that the grid is at the very back of // the Z order. glClear(GL_DEPTH_BUFFER_BIT); nogrid:; } // Draw the active group; this does stuff like the mesh and edges. (SK.GetGroup(activeGroup))->Draw(); // Now draw the entities if(showHdnLines) glDisable(GL_DEPTH_TEST); Entity::DrawAll(); // Draw filled paths in all groups, when those filled paths were requested // specially by assigning a style with a fill color, or when the filled // paths are just being filled by default. This should go last, to make // the transparency work. Group *g; for(g = SK.group.First(); g; g = SK.group.NextAfter(g)) { if(!(g->IsVisible())) continue; g->DrawFilledPaths(); } glDisable(GL_DEPTH_TEST); // Draw the constraints for(i = 0; i < SK.constraint.n; i++) { SK.constraint.elem[i].Draw(); } // Draw the traced path, if one exists glLineWidth(Style::Width(Style::ANALYZE)); ssglColorRGB(Style::Color(Style::ANALYZE)); SContour *sc = &(SS.traced.path); glBegin(GL_LINE_STRIP); for(i = 0; i < sc->l.n; i++) { ssglVertex3v(sc->l.elem[i].p); } glEnd(); // And the naked edges, if the user did Analyze -> Show Naked Edges. glLineWidth(Style::Width(Style::DRAW_ERROR)); ssglColorRGB(Style::Color(Style::DRAW_ERROR)); ssglDrawEdges(&(SS.nakedEdges), true); // Then redraw whatever the mouse is hovering over, highlighted. glDisable(GL_DEPTH_TEST); ssglLockColorTo(Style::Color(Style::HOVERED)); hover.Draw(); // And finally draw the selection, same mechanism. ssglLockColorTo(Style::Color(Style::SELECTED)); for(Selection *s = selection.First(); s; s = selection.NextAfter(s)) { s->Draw(); } ssglUnlockColor(); // If a marquee selection is in progress, then draw the selection // rectangle, as an outline and a transparent fill. if(pending.operation == DRAGGING_MARQUEE) { Point2d begin = ProjectPoint(orig.marqueePoint); double xmin = min(orig.mouse.x, begin.x), xmax = max(orig.mouse.x, begin.x), ymin = min(orig.mouse.y, begin.y), ymax = max(orig.mouse.y, begin.y); Vector tl = UnProjectPoint(Point2d::From(xmin, ymin)), tr = UnProjectPoint(Point2d::From(xmax, ymin)), br = UnProjectPoint(Point2d::From(xmax, ymax)), bl = UnProjectPoint(Point2d::From(xmin, ymax)); glLineWidth((GLfloat)1.3); ssglColorRGB(Style::Color(Style::HOVERED)); glBegin(GL_LINE_LOOP); ssglVertex3v(tl); ssglVertex3v(tr); ssglVertex3v(br); ssglVertex3v(bl); glEnd(); ssglColorRGBa(Style::Color(Style::HOVERED), 0.10); glBegin(GL_QUADS); ssglVertex3v(tl); ssglVertex3v(tr); ssglVertex3v(br); ssglVertex3v(bl); glEnd(); } // An extra line, used to indicate the origin when rotating within the // plane of the monitor. if(SS.extraLine.draw) { glLineWidth(1); ssglLockColorTo(Style::Color(Style::DATUM)); glBegin(GL_LINES); ssglVertex3v(SS.extraLine.ptA); ssglVertex3v(SS.extraLine.ptB); glEnd(); } // A note to indicate the origin in the just-exported file. if(SS.justExportedInfo.draw) { ssglColorRGB(Style::Color(Style::DATUM)); Vector p = SS.justExportedInfo.pt, u = SS.justExportedInfo.u, v = SS.justExportedInfo.v; glLineWidth(1.5); glBegin(GL_LINES); ssglVertex3v(p.Plus(u.WithMagnitude(-15/scale))); ssglVertex3v(p.Plus(u.WithMagnitude(30/scale))); ssglVertex3v(p.Plus(v.WithMagnitude(-15/scale))); ssglVertex3v(p.Plus(v.WithMagnitude(30/scale))); glEnd(); ssglWriteText("(x, y) = (0, 0) for file just exported", DEFAULT_TEXT_HEIGHT, p.Plus(u.ScaledBy(10/scale)).Plus(v.ScaledBy(10/scale)), u, v, NULL, NULL); ssglWriteText("press Esc to clear this message", DEFAULT_TEXT_HEIGHT, p.Plus(u.ScaledBy(40/scale)).Plus( v.ScaledBy(-(DEFAULT_TEXT_HEIGHT)/scale)), u, v, NULL, NULL); } // And finally the toolbar. if(SS.showToolbar) { ToolbarDraw(); } }