Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/COM classes/ShapeEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,22 @@ STDMETHODIMP CShapeEditor::put_SnapBehavior(tkLayerSelection newVal)
return S_OK;
}

// *******************************************************
// get_SnapMode()
// *******************************************************
STDMETHODIMP CShapeEditor::get_SnapMode(tkSnapMode* pVal)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
*pVal = _snapMode;
return S_OK;
}
STDMETHODIMP CShapeEditor::put_SnapMode(tkSnapMode newVal)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
_snapMode = newVal;
return S_OK;
}

// *******************************************************
// EditorState
// *******************************************************
Expand Down
4 changes: 4 additions & 0 deletions src/COM classes/ShapeEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class ATL_NO_VTABLE CShapeEditor :
_highlightShapes = lsAllLayers;
_snapTolerance = 10;
_snapBehavior = lsAllLayers;
_snapMode = smVerticesAndLines;
_state = esNone;
_mapCallback = NULL;
_isSubjectShape = false;
Expand Down Expand Up @@ -113,6 +114,8 @@ class ATL_NO_VTABLE CShapeEditor :
STDMETHOD(put_HighlightVertices)(tkLayerSelection newVal);
STDMETHOD(get_SnapBehavior)(tkLayerSelection* pVal);
STDMETHOD(put_SnapBehavior)(tkLayerSelection newVal);
STDMETHOD(get_SnapMode)(tkSnapMode* pVal);
STDMETHOD(put_SnapMode)(tkSnapMode newVal);
STDMETHOD(get_EditorState)(tkEditorState* pVal);
STDMETHOD(put_EditorState)(tkEditorState newVal);
STDMETHOD(StartEdit)(LONG LayerHandle, LONG ShapeIndex, VARIANT_BOOL* retVal);
Expand Down Expand Up @@ -154,6 +157,7 @@ class ATL_NO_VTABLE CShapeEditor :
ICallback * _globalCallback;
VARIANT_BOOL _visible;
tkLayerSelection _highlightShapes;
tkSnapMode _snapMode;
double _snapTolerance;
tkLayerSelection _snapBehavior;
EditorBase* _activeShape;
Expand Down
35 changes: 35 additions & 0 deletions src/COM classes/Shapefile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3174,6 +3174,41 @@ STDMETHODIMP CShapefile::GetClosestVertex(double x, double y, double maxDistance
return S_OK;
}

// *****************************************************************
// GetClosestSnapPosition()
// *****************************************************************
STDMETHODIMP CShapefile::GetClosestSnapPosition(double x, double y, double maxDistance,
long* shapeIndex, double* fx, double* fy, double* distance, VARIANT_BOOL* retVal)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

*retVal = VARIANT_FALSE;
*shapeIndex = -1;

bool result = false;
if (maxDistance <= 0.0)
{
// search through all shapefile
std::vector<long> ids;
for (size_t i = 0; i < _shapeData.size(); i++)
{
ids.push_back(i);
}
result = ShapefileHelper::GetClosestSnapPosition(this, x, y, maxDistance, ids, shapeIndex, *fx, *fy, *distance);
}
else
{
std::vector<long> ids;
Extent box(x - maxDistance, x + maxDistance, y - maxDistance, y + maxDistance);
if (this->SelectShapesCore(box, 0.0, SelectMode::INTERSECTION, ids, false))
{
result = ShapefileHelper::GetClosestSnapPosition(this, x, y, maxDistance, ids, shapeIndex, *fx, *fy, *distance);
}
}
*retVal = result ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}

// *****************************************************************
// HasInvalidShapes()
// *****************************************************************
Expand Down
1 change: 1 addition & 0 deletions src/COM classes/Shapefile.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ class ATL_NO_VTABLE CShapefile :
STDMETHOD(EditAddShape)(IShape* shape, long* shapeIndex);
STDMETHOD(EditAddField)(BSTR name, FieldType type, int precision, int width, long* fieldIndex);
STDMETHOD(GetClosestVertex)(double x, double y, double maxDistance, long* shapeIndex, long* pointIndex, double* distance, VARIANT_BOOL* retVal);
STDMETHOD(GetClosestSnapPosition)(double x, double y, double maxDistance, long* shapeIndex, double* fx, double* fy, double* distance, VARIANT_BOOL* retVal);
STDMETHOD(get_ShapeCategory2)(long ShapeIndex, BSTR* categoryName);
STDMETHOD(put_ShapeCategory2)(long ShapeIndex, BSTR categoryName);
STDMETHOD(get_ShapeCategory3)(long ShapeIndex, IShapefileCategory** category);
Expand Down
70 changes: 69 additions & 1 deletion src/ComHelpers/ShapefileHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,10 +382,78 @@ bool ShapefileHelper::GetClosestPoint(IShapefile* sf, double x, double y, double
shp->Release();
}
}
// dist = minDist;
dist = minDist;
return minDist < maxDistance;
}

// *****************************************************************
// GetClosestPoint()
// *****************************************************************
bool ShapefileHelper::GetClosestSnapPosition(IShapefile* sf, double x, double y, double maxDistance, std::vector<long>& ids,
long* shapeIndex, double& fx, double& fy, double& dist)
{
if (!sf) return false;

VARIANT_BOOL vb;
double minDist = DBL_MAX;

IPoint* pnt = NULL;
IShape* ptShp = NULL;
IShape* resShp = NULL;

for (long id : ids)
{
VARIANT_BOOL visible;
sf->get_ShapeVisible(id, &visible);
if (!visible) continue;
Copy link
Contributor

@jerryfaust jerryfaust Jan 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's best not to treat a VARIANT_BOOL as a bool. Since VARIANT_TRUE is a short integer (-1), and bool is an intrinsic type, you may not always get the expected result. It would be better to say something like
if (visible == VARIANT_FALSE) continue;

This may seem a trivial point, but we've had issues in the past when mixing these types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty new to C and C++, most of the changes were made by looking at other code and copying what I need, thanks for the explanation. Can you point me to a good reference for this in particular?

Copy link
Contributor

@jerryfaust jerryfaust Jan 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a pretty good explanation, noting particularly to beware of comparing the various 'true' values:

BOOL vs. VARIANT_BOOL vs. BOOLEAN vs. bool

I should add that being a COM interface, our API needs to use VARIANT_BOOL. However, internally, it is often beneficial to use bool since it is more concise and straightforward. Only convert back to VARIANT_BOOL as necessary.


IShape* shp = NULL;
sf->get_Shape(id, &shp);

if (shp != NULL)
{
// Create point shape
ComHelper::CreateShape(&ptShp);
ptShp->Create(SHP_POINT, &vb);
if (vb != VARIANT_TRUE)
{
shp->Release();
pnt->Release();
continue;
}

// Add point
ComHelper::CreatePoint(&pnt);
pnt->put_X(x);
pnt->put_Y(y);
long position = 0;
ptShp->InsertPoint(pnt, &position, &vb);
pnt->Release();

// Get closest points:
shp->ClosestPoints(ptShp , &resShp);
ptShp->Release();
shp->Release();

if (resShp != NULL) {
// Get the point snapped on geometry
double xPnt, yPnt;
resShp->get_XY(0, &xPnt, &yPnt, &vb);

// Check if this is allowed and/or smaller than the previous found point:
const double distance = sqrt(pow(x - xPnt, 2.0) + pow(y - yPnt, 2.0));
if (distance < minDist && distance < maxDistance) {
fx = xPnt;
fy = yPnt;
minDist = distance;
}
}
}
}
dist = minDist;
return minDist < maxDistance;
}

// ********************************************************************
// PointInPolygon()
// ********************************************************************
Expand Down
2 changes: 2 additions & 0 deletions src/ComHelpers/ShapefileHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class ShapefileHelper
static IShapefile* CloneSelection(IShapefile* sf);
static bool ShapeSelected(IShapefile* sf, int shapeIndex);
static bool GetClosestPoint(IShapefile* sf, double x, double y, double maxDistance, std::vector<long>& ids, long* shapeIndex, long* pointIndex, double& dist);
static bool GetClosestSnapPosition(IShapefile * sf, double x, double y, double maxDistance, std::vector<long>& ids, long * shapeIndex, double& fx, double& fy, double & dist);
static bool GetClosestPointOnSegment(double ax, double ay, double bx, double by, double px, double py, double * rx, double * ry);
static bool PointInPolygon(IShapefile* sf, long ShapeIndex, double x, double y);
static bool BoundsWithinPolygon(IShapefile* sf, int shapeIndex, double b_minX, double b_minY, double b_maxX, double b_maxY);
static bool ShapeTypeIsM(IShapefile* sf);
Expand Down
39 changes: 23 additions & 16 deletions src/Control/Map_Edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,32 @@ bool CMapView::SnappingIsOn(bool shift)
// ************************************************************
bool CMapView::HandleOnMouseMoveShapeEditor(int x, int y, long nFlags)
{

tkLayerSelection behavior;
_shapeEditor->get_SnapBehavior(&behavior);

double projX, projY;
VARIANT_BOOL snapped = FindSnapPointCore(x, y, &projX, &projY);
if (!snapped) {
Copy link
Contributor

@jerryfaust jerryfaust Jan 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to earlier, FindSnapPointCore returns a VARIANT_BOOL, and you're setting it into a bool variable. Either 'snapped' should be changed to VARIANT_BOOL, OR perhaps instead, we should change FindSnapPointCore to return a bool, since it is an internal function and is more easily handled with the standard bool data type.

PixelToProjection(x, y, projX, projY);
GetEditorBase()->ClearSnapPoint();
}
else {
double sX, sY;
ProjToPixel(projX, projY, &sX, &sY);
GetEditorBase()->SetSnapPoint(sX, sY, true);
}


if ((_dragging.Operation == DragMoveVertex ||
_dragging.Operation == DragMoveShape ||
_dragging.Operation == DragMovePart)) // && (nFlags & MK_LBUTTON) && _leftButtonDown
{
_dragging.Snapped = false;
tkLayerSelection behavior;
_shapeEditor->get_SnapBehavior(&behavior);
if (behavior == lsAllLayers && _dragging.Operation == DragMoveVertex)
{
double xFound, yFound;
if (this->FindSnapPointCore(x, y, &xFound, &yFound)) {
double xNew, yNew;
ProjToPixel(xFound, yFound, &xNew, &yNew);
_dragging.SetSnapped(xFound, yFound);
}
}
if (behavior == lsAllLayers && _dragging.Operation == DragMoveVertex && snapped)
_dragging.SetSnapped(projX, projY);
else
GetEditorBase()->ClearSnapPoint();
_dragging.HasMoved = true;

// in case of vertex moving underlying data is changed in the process (to update displayed length);
Expand Down Expand Up @@ -122,12 +132,8 @@ bool CMapView::HandleOnMouseMoveShapeEditor(int x, int y, long nFlags)
}
else
{
tkEditorBehavior behavior;
_shapeEditor->get_EditorBehavior(&behavior);
EditorBase* base = GetEditorBase();
bool handled = false;
double projX, projY;
this->PixelToProjection(x, y, projX, projY);

// highlighting of vertices
if (behavior == ebVertexEditor)
Copy link
Contributor

@jerryfaust jerryfaust Jan 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to look further into this - 'behavior' was originally defined (within this block of code) as tkEditorBehavior, but you have redefined it (above) as tkLayerSelection, and assigned the result of get_SnapBehavior. It seems that this test (behavior == ebVertexEditor) may not be giving back the expected result.

Expand All @@ -146,7 +152,7 @@ bool CMapView::HandleOnMouseMoveShapeEditor(int x, int y, long nFlags)
}
else {
if (base->ClearHighlightedVertex()) {
_canUseMainBuffer = false;
_canUseMainBuffer = false;
return true;
}
}
Expand All @@ -155,6 +161,7 @@ bool CMapView::HandleOnMouseMoveShapeEditor(int x, int y, long nFlags)
// highlighting parts
if (behavior == ebPartEditor) //if (nFlags & MK_CONTROL) {
{

if (base->ClearHighlightedVertex())
_canUseMainBuffer = false;

Expand Down
3 changes: 3 additions & 0 deletions src/Control/Map_Events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,10 @@ void CMapView::OnMouseMove(UINT nFlags, CPoint point)
snapped = this->FindSnapPointCore(point.x, point.y, &x, &y);
if (snapped) {
ProjToPixel(x, y, &x, &y);
_shapeEditor->GetActiveShape()->SetSnapPoint(x, y, true);
}
else
_shapeEditor->GetActiveShape()->ClearSnapPoint();
}
shp->SetMousePosition(x, y);
refreshNeeded = true;
Expand Down
55 changes: 32 additions & 23 deletions src/Control/Map_Identifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ VARIANT_BOOL CMapView::FindSnapPoint(double tolerance, double xScreen, double yS
double distance;

double minDist = DBL_MAX;
IShapefile* foundShapefile = NULL;
long foundShapeIndex;
long foundPointIndex;

bool digitizing = EditorHelper::IsDigitizingCursor((tkCursorMode)m_cursorMode);
tkLayerSelection behavior;
_shapeEditor->get_SnapBehavior(&behavior);
tkSnapMode mode;
_shapeEditor->get_SnapMode(&mode);
long currentHandle = -1;
bool currentLayerOnly = behavior == lsActiveLayer && digitizing;
if (currentLayerOnly)
_shapeEditor->get_LayerHandle(&currentHandle);

bool result = false;
for (long i = 0; i < this->GetNumLayers(); i++)
{
long layerHandle = this->GetLayerHandle(i);
Expand All @@ -68,31 +68,40 @@ VARIANT_BOOL CMapView::FindSnapPoint(double tolerance, double xScreen, double yS
sf->get_Snappable(&snappable);
if (snappable)
{
sf->GetClosestVertex(x, y, maxDist, &shapeIndex, &pointIndex, &distance, &vb);
if (vb)
{
if (distance < minDist)
double xF, yF;
bool snapped = false;
// Try snapping to a vertex first:
if (mode == smVertices || mode == smVerticesAndLines) {
sf->GetClosestVertex(x, y, maxDist, &shapeIndex, &pointIndex, &distance, &vb);
if (vb && distance < minDist)
{
IShape* shape = NULL;
sf->get_Shape(shapeIndex, &shape);
if (shape)
{
minDist = distance;
shape->get_XY(pointIndex, &xF, &yF, &vb);
shape->Release();
snapped = true;
}
}
}
// If not snapped to a vertex, maybe try to snap to a segment:
if (!snapped && (mode == smVerticesAndLines || mode == smLines)) {
sf->GetClosestSnapPosition(x, y, maxDist, &shapeIndex, &xF, &yF, &distance, &vb);
if (vb && distance < minDist)
{
minDist = distance;
foundShapefile = sf;
foundPointIndex = pointIndex;
foundShapeIndex = shapeIndex;
snapped = true;
}
}
}
}
}

bool result = false;
if (minDist != DBL_MAX && foundShapefile)
{
IShape* shape = NULL;
foundShapefile->get_Shape(foundShapeIndex, &shape);
if (shape)
{
shape->get_XY(foundPointIndex, xFound, yFound, &vb);
shape->Release();
result = true;
if (snapped) {
*xFound = xF;
*yFound = yF;
result = true;
}
}
}
}
return result;
Expand Down
5 changes: 5 additions & 0 deletions src/Editor/ActiveShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ void ActiveShape::DrawData( Gdiplus::Graphics* g, bool dynamicBuffer,
DrawPolygonArea(g, polyData, polySize, dynamicBuffer);
delete[] polyData;
}

// finally draw the snap point position if needed
if (_showSnapPoint) {
g->DrawRectangle(&_redPen, (int)(_snapPointX - 3.0f + 0.5f), (int)(_snapPointY - 3.0f + 0.5f), 6, 6);
}
}

// ****************************************************************
Expand Down
7 changes: 7 additions & 0 deletions src/Editor/ActiveShape.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class ActiveShape: public GeoShape
_highlightedPart = -1;
_inputMode = simMeasuring;

_showSnapPoint = false;
_snapPointX = 0;
_snapPointY = 0;

AnglePrecision = 1;
AngleFormat = afDegrees;
AreaDisplayMode = admMetric;
Expand Down Expand Up @@ -90,6 +94,9 @@ class ActiveShape: public GeoShape
int _highlightedVertex;
int _selectedPart;
int _highlightedPart;
bool _showSnapPoint;
double _snapPointX;
double _snapPointY;

public:

Expand Down
Loading