macOS - Move mouse by value - swift

I have an app that receives data from an iOS app through bluetooth and it is supposed to move the mouse cursor.
The problem is that I get some weird functionality at y axis (x is fine).
The input looks like dx~dy where dx,dy are the values to move the cursor by. Here is an example:
-3.0~2.0
An example of my output:
Mouse loc: (596.0, 309.0) New Mouse loc: (603.0, 311.0)
Mouse loc: (603.0, 489.0) New Mouse loc: (610.0, 491.0)
Mouse loc: (610.0, 309.0) New Mouse loc: (615.0, 311.5)
Mouse loc: (615.0, 489.0) New Mouse loc: (618.0, 491.0)
Mouse loc: (618.0, 309.0) New Mouse loc: (618.5, 312.5)
As you can see first it has a lower y coordinate than a higher one. So basically the mouse keeps "jumping" up and down.
Here is my code that handles the input:
let mouseLoc = NSEvent.mouseLocation()
let newLoc = CGPoint(x: mouseLoc.x-CGFloat(x), y: mouseLoc.y+CGFloat(y))
CGDisplayMoveCursorToPoint(0, newLoc)
EDIT: in the test case I had values between 0 and 2 so there is no way to have a difference of 100 between two states

Cocoa and Core Graphics (a.k.a. Quartz) use different coordinate systems. In Cocoa, the origin is at the lower left of the primary screen and y increases as you go up. In Core Graphics, the origin is at the top left of the primary screen and y increases as you go down.
Since you're using a Core Graphics function to move the cursor, you need to convert from Cocoa's coordinate system.
var mouseLoc = NSEvent.mouseLocation()
mouseLoc.y = NSHeight(NSScreen.screens()![0].frame) - mouseLoc.y;
// etc.

Related

How to convert the position in CGDisplayBounds() to global coordinate ( like NSEvent.mouseLocation) in Swift

I'm a newbie in Swift and MacOS.
I gonna find a method to get the exact display coordinate
NSEvent.mouseLocation
I have found method in CoreGraphic :
func CGDisplayBounds(_ display: CGDirectDisplayID) -> CGRect
but the coordinate is different.
I can workaround to apply a method to mathematically method to convert point Y.
But is there any method to get or convert the position programmatically?
I expect to get the same coordinate with NSEvent.mouseLocation.
Thank for your attention.
It returns to the same coordinate with mouse location.
As you noted, CoreGraphics has what Apple calls ‘flipped’ geometry, with the origin at the top left and the y coordinates increasing toward the bottom of the screen. This is the geometry used by most computer graphics systems.
AppKit prefers what Apple calls ‘non-flipped’, with the origin at the bottom left and the y coordinates increasing toward the top of the screen. This is the geometry normally used in mathematics.
The origin (0, 0) of the CoreGraphics global geometry is always at the top-left of the ‘main’ display (identified by CGMainDisplayID()). The origin of the AppKit global geometry is always at the bottom-left of the main display. To convert between the two geometries, subtract your y coordinate from the height of the main display.
That is:
extension CGPoint {
func convertedToAppKit() -> CGPoint {
return .init(
x: x,
y: CGDisplayBounds(CGMainDisplayID()).height - y
)
}
func convertedToCoreGraphics() -> CGPoint {
return .init(
x: x,
y: CGDisplayBounds(CGMainDisplayID()).height - y
)
}
}
You may notice that these two functions have the same implementation. You don't really need two functions; you can just use one. It converts in both directions.
Calling CGDisplayBounds(CGMainDisplayID()) might also be inefficient. You might want to cache the value or batch your transformations if you're going to be doing a lot of them. But if you cache the value, you'll want to subscribe to NSApplication.didChangeScreenParametersNotification so you can update the cached value if it needs to change.

RealityKit – Create line between two points in 3d space

How to create a line between two points in 3d space with RealityKit?
There are examples of creating lines between two points in Scenekit, however, there are basically none using RealityKit.
To create the line, I've created a rectangle model entity and placed it between my first touched point and the current touched point. From here, all I would need to do is rotate the rectangle to face the current touched point. However, using the simd_quatf(from: to:) doesn't work as intended.
rectangleModelEntity.transform.rotation = simd_quatf(from: firstTouchedPoint,
to: currTouchedPoint)
If I were to touch a point and then drag directly downwards, the rectangle model should be to be a straight line between first touched and current touched point, but it stays horizontal with a slight tilt.
To solve this, I tried getting the angle between my initially horzontal line as a vector and a vector from the first touched to current touched point
let startVec = currTouchedPoint - firstTouchedPoint
let endVec = endOfModelEntityPoint - modelEntityCenterPoint
let lengthVec = simd_length(cross(startVec, endVec))
let theta = atan2(lengthVec, dot(startVec, endVec))
This gives me the angle between two vectors in 3d space, which seems correct, when I checked it gave me 90 degrees when touching and dragging directly between it.
The problem is I don't know what the axis to rotate it on should be. Since this is 3d space, the line doesn't need to be on a 2d plane, the current touched position can be downwards and in front of the starting touch position.
rectangleModelEntity = simd_quatf(angle: theta, axis: ???)
Personally, I'm not even too sure if the above is the correct solution to creating a line between two points. In theory it's rather basic, create a rectangle with low height/depth to mimic a line, position it in the center of the starting and current touch point then rotate it so it's oriented correctly.
What should be the axis for the above degrees between two vectors?
Is there a better method of creating two lines between points in 3d space with RealityKit/ARKit?
I have implemented using a box. Let me know if you have a better way.
let midPosition = SIMD3(x:(position1.x + position2.x) / 2,
y:(position1.y + position2.y) / 2,
z:(position1.z + position2.z) / 2)
let anchor = AnchorEntity()
anchor.position = midPosition
anchor.look(at: position1, from: midPosition, relativeTo: nil)
let meters = simd_distance(position1, position2)
let lineMaterial = SimpleMaterial.init(color: .red,
roughness: 1,
isMetallic: false)
let bottomLineMesh = MeshResource.generateBox(width:0.025,
height: 0.025/2.5,
depth: meters)
let bottomLineEntity = ModelEntity(mesh: bottomLineMesh,
materials: [lineMaterial])
bottomLineEntity.position = .init(0, 0.025, 0)
anchor.addChild(bottomLineEntity)
The axis is the cross product of the direction your object is facing at the beginning and the direction it should be facing now.
Like if it's at position p1=[x1,y1,z1], initially facing d1=[0, 0, -1], and you want it to face a point p2=[x, y, z] the axis would be the cross product: |d1|✕|p2 - p1|.
May have to swap the two around, or just negate the angle though, depending on how it works out.

leaflet editable restrict draw to a specific area

In Leaflet.Editable I want to confine/limit my customers to draw only in a specific area/bounds.
actually im trying to limit them to (90, -90, 180, -180) bounds of map..
maxBounds: [[-90, -180], [90, 180]]
I was not able to find anything anywhere and it seems that i am missing something.
CODEPEN DEMO
please help.
EDIT:
the Y axis is blocking correctly and mouse cannot stretch shape beyond top and bottom.
the problem is in X axis (as seen in pictures)
as for now i solved it with after save check and clear shape if it out of map bounds (BAD USER EXPERIENCE). i need a mouse confinement just like y axis does.
Without knowing your use case (why the whole world map??) Quickest and easiest fix would be to simply set the map's minZoom to something a bit higher, for example, I found that minZoom: 5 was adequate except for cases where the map was both really short and really wide (which is rarely the case in most apps I've seen).
But the real fix involves writing your own custom overrides for dragging markers and shapes.
According to API doc the L.Editable plugin allows you to override a bunch of stuff including the VertexMarker class, via map.editTools.options.vertexMarkerClass.
Fixed codepen: http://codepen.io/anon/pen/GrPpRY?editors=0010
This snippet of code that allows you to constrain the longitude for dragging vertex markers by correcting values under -180 and over 180 is this:
// create custom vertex marker editor
var vertexMarkerClass = L.Editable.VertexMarker.extend({
onDrag: function(e) {
e.vertex = this;
var iconPos = L.DomUtil.getPosition(this._icon),
latlng = this._map.layerPointToLatLng(iconPos);
// fix out of range vertex
if (latlng.lng < -180) {
e.latlng.lng = latlng.lng = -180;
this.setLatLng(latlng);
}
if (latlng.lng > 180) {
e.latlng.lng = latlng.lng = 180;
this.setLatLng(latlng);
}
this.editor.onVertexMarkerDrag(e);
this.latlng.update(latlng);
this._latlng = this.latlng; // Push back to Leaflet our reference.
this.editor.refresh();
if (this.middleMarker) this.middleMarker.updateLatLng();
var next = this.getNext();
if (next && next.middleMarker) next.middleMarker.updateLatLng();
}
});
// attach custom editor
map.editTools.options.vertexMarkerClass = vertexMarkerClass;
I didn't code for dragging the shape as a whole (the rectangle, in this case). While the VertexMarker fix should address all kinds of vertex dragging, you need to override each shape's drag handler to properly constrain the bounds. And if bounds are exceeded, crop the shape appropriately. As was pointed out, Leaflet already does this for latitude, but because Leaflet allows wrapping the map around horizontally you have your essential problem. Using rec.on("drag") to correct the bounds when they cross over your min/max longitude is the only way to address it. It is basically the same solution as I have laid out for the vertexMarkerClass - actual code left as exercise for the diligent reader.

Mapbox Icons/Markers "BearingSnap" or Snap to Position

Is there a way to move icons/markers to a certain location where it will then "snap" to the location?
For example, chess games on the computer where when you move a chess piece to the correct square, it will snap to that position when you let go of the piece near/around the square.
So what I want is to move a marker or an icon to a certain location, let's say the capital of California, and the marker will "snap" to the location that I want when I move it and let go of the marker near the location. But I also want to still be able to move the marker if I want to.
I know Mapbox gl has bearingSnap which snaps the map back to north after the user rotates the map but I can't find anything for just icons/markers and I don't believe I can use bearingSnap for it.
Thanks.
You can use Turfs distance function: turf.distance(pt1, pt2) to measure distances between 2 points. If then the calculated distance is under a certain threshold, you can set the location of your dragging point to the location of your snap point.
I have you a working example in a jsfiddle:
https://jsfiddle.net/andi_lo/nmc4kprn/
function onMove(e) {
if (!isDragging) return;
var coords = e.lngLat;
// Set a UI indicator for dragging.
canvas.style.cursor = 'grabbing';
// Update the Point feature in `geojson` coordinates
// and call setData to the source layer `point` on it.
geojson.features[0].geometry.coordinates = [coords.lng, coords.lat];
map.getSource('point').setData(geojson);
let snapTo = map.getSource('snap')._data;
turf.featureEach(snapTo, (feature) => {
let dist = turf.distance(feature, turf.point([coords.lng, coords.lat]));
console.log(dist);
// if the distance of the dragging point is under a certain threshold
if (dist < 500) {
// set the location of the dragging point to the location of the snapping point
geojson.features[0].geometry.coordinates = feature.geometry.coordinates;
map.getSource('point').setData(geojson);
}
});
}
This is a feature you can and should implement upstream of GL JS. When you construct the coordinate of the marker or GeoJSON feature, snap it to the desired grid.

Unity - get position of UI Slider Handle

I am working on Unity 4.7 project and need to create shooting on the target. I simulated gunpoint using horizontal and vertical slider moving on the time. When I click the button I need to memorize x and y coordinates of handles and instantiate bullet hole at this point but don't know how to get cords of sliders handle. It is possible to get values but it seems that it doesn't correspond to coordinates. If horizontal slider changes its value for 1, would its handle change x position for 1?
Use this then:
public static Vector3 GetScreenPositionFromWorldPosition(Vector3 targetPosition)
{
Vector3 screenPos = Camera.main.WorldToScreenPoint(targetPosition);
return screenPos;
}
Have the reference to Handles of the horizontal and vertical sliders, and use them like:
Vector3 pos = GetScreenPositionFromWorldPosition(horizontalHandle.transform.position);