I would like to create Specification to dynamic search.
In database I have fields like radius, width and height - depends on type of shape.
I want to add request paramter like for example areaTo - which will be returing shapes with area smaller or equal to paramter.
I was thinking about adding some Predicate but I can not find any example how to do it.
What I mean, I would like to add something like that:
public static Specification<ShapeEntity> areaTo(double areaTo) {
return (root, query, criteriaBuilder) -> {
double area;
switch (root.get("type").toString()) {
case "CIRCLE":
area = Math.pow(Double.parseDouble(root.get("radius").toString()), 2) * Math.PI;
break;
case "RECTANGLE":
area = Double.parseDouble(root.get("width").toString()) * Double.parseDouble(root.get("height").toString());
break;
case "SQUARE":
area = Math.pow(Double.parseDouble(root.get("width").toString()), 2);
break;
default:
throw new IllegalArgumentException();
}
return criteriaBuilder.lessThanOrEqualTo(????, areaTo);
};
}
I found a solution that somewhat answers your question, what you need to create here is an Expression.
you could try to modify this code to suit what you need:
private Specification<Shape> areaTo(double areaTo, String type) {
return (root, query, criteriaBuilder) -> {
Expression<Double> area;
switch (type) {
case "CIRCLE":
Expression<Double> radius = root.get("radius");
Expression<Double> power = criteriaBuilder.prod(radius, radius);
area = criteriaBuilder.prod(power, Math.PI);
break;
case "RECTANGLE":
Expression<Double> width = root.get("width");
Expression<Double> height = root.get("height");
area = criteriaBuilder.prod(width, height);
break;
case "SQUARE":
Expression<Double> width_s = root.get("width");
area = criteriaBuilder.prod(width_s, width_s);
break;
default:
throw new IllegalArgumentException();
}
return criteriaBuilder.lessThanOrEqualTo(area, areaTo);
};
}
your switch (root.get("type").toString()) won't work in the switch statement because there is no value return here, they creating a query. In this situation, you could create a Predicate for each type of shape and then add them to criteriaBuilder with operator or
for further information about my solution you should take a look at this link
Related
I am having issues converting a piece of JAVA based code into ECMAScript/TypeScript, may someone can help. There are two parts I struggle to convert a) a constructor overload I think and b) a self referencing push. Maybe there is a different way to write this?
class Finder {
PVector location;
PVector velocity;
float diameter;
Pvector origin = new PVector(width / 2, height/2);
Finder(int x, int y) {
location = new PVector(width/2, height/2);
velocity = new PVector(x, y);
diameter = 8;
}
// this is a) where I struggle to convert
Finder(Finder parent) {
location = parent.location.get();
velocity = parent.velocity.get();
float area = PI*sq(parent.diameter/2);
float newDiam = sqrt(area/2/PI)*2;
diameter = newDiam;
parent.diameter = newDiam;
}
void update() {
if(origin.dist(location)> 300){
// nothing
} else if (diameter>0.5) {
location.add(velocity);
PVector bump = new PVector(random(-1, 1), random(-1, 1));
bump.mult(0.1);
velocity.add(bump);
velocity.normalize();
if (random(0, 1)<0.02) {
// this is b) where I struggle to convert
paths = (Finder[]) append(paths, new Finder(this));
}
}
}
}
Finder[] paths;
Regarding part a, treat is a function that returns a copy (new instance with copied properties from argument instance):
(JS doesn't support overloaded constructors, hence simply using a method instead of a constructor should suffice)
e.g.
copy(parent) {
location = parent.location.copy();
velocity = parent.velocity.copy();
let area = PI*sq(parent.diameter/2);
let newDiam = sqrt(area/2/PI)*2;
diameter = newDiam;
// this looks a bit sus to me: why should we change the parent ?
parent.diameter = newDiam;
}
Regarding part b I can infer that paths is a Finder[] in the global scope (e.g. main sketch variables). Is so, that will be a plain js array when you port to p5.js and in js arrays are dynamic so you should be able to simply do use paths.push(this.copy()) instead.
(If you want to test in the Processing sketch, swap the Finder[] paths line to ArrayList<Finder> paths = new ArrayList<Finder>() and use paths.add(New Finder(this)); instead paths = (Finder[]) append(paths, new Finder(this));)
Okay so I'm making a photography game where when you 'take a photo', Unity sends a few raycasts forward to check if certain tagged items are in the photo (all within the cameras FOV). My problem is, this seems to work intermittently! Sometimes it finds the tagged objects, other times it will be right in front of the view yet it will miss it completely! Can anyone advise about what I'm doing wrong?
public static Transform target;
public static GameObject[] targetName;
public static float length = 250f;
public static Transform thisObject;
// Start is called before the first frame update
void Start()
{
thisObject = GameObject.Find("Main Camera").GetComponent<Transform>();
//target = GameObject.FindGameObjectWithTag("Trees").transform;
}
// Update is called once per frame
void Update()
{
//InFront();
//HasLineOfSight("Trees");
}
public static bool InFront(Transform target1)
{
Vector3 directionToTarget = thisObject.position - target1.position;
float angleOnXAxis = Vector3.Angle(thisObject.right, directionToTarget);
float angleOnYAxis = Vector3.Angle(thisObject.up, directionToTarget);
//Debug.Log(angleOnYAxis);
if (Mathf.Abs(angleOnXAxis) < 130 && Mathf.Abs(angleOnXAxis) > 50
&& Mathf.Abs(angleOnYAxis) < 115 && Mathf.Abs(angleOnYAxis) > 62)
{
//Debug.DrawLine(transform.position, target.position, Color.green);
return true;
}
return false;
}
public static bool HasLineOfSight(string objectTag)
{
RaycastHit hit;
Vector3 direction = target.position - thisObject.position;
//Debug.Log(direction);
if (Physics.Raycast(thisObject.position, direction, out hit, length))
{
if (hit.transform.tag == objectTag)
{
Debug.DrawRay(thisObject.position, direction * 0.96f, Color.red);
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
public static GameObject SortObjects(string objectTag)
{
targetName = GameObject.FindGameObjectsWithTag(objectTag);
GameObject closestObject = null;
for (int i = 0; i < targetName.Length; i++)
{
if (Vector3.Distance(thisObject.position,
targetName[i].transform.position) <= length)
{
if (InFront(targetName[i].transform))
{
if (closestObject == null)
{
closestObject = targetName[i];
}
else
{
if (Vector3.Distance(targetName[i].transform.position, thisObject.position) <= Vector3.Distance(closestObject.transform.position, thisObject.position))
{
closestObject = targetName[i];
}
}
}
}
}
return closestObject;
}
public static bool ObjectCheck(string objectTag)
{
//Debug.Log(SortObjects(objectTag));
if (SortObjects(objectTag) != null)
{
target = SortObjects(objectTag).transform;
//Debug.Log(target);
if (InFront(target) && HasLineOfSight(objectTag))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
I'm essentially calling ObjectCheck() with the tag I want to check for to get the closest, visible, object with that tag. What is wrong with this code??
In your script, only the closest object to the main camera gets checked. SortObjects() determines the closest tagged object, and then you only handle that single object in ObjectCheck(). - That object might be obstructed by something else, so the method returns false. And other tagged objects that are actually visible, are not picked up this way...
So, you could rename and change your SortObjects() function to check for both conditions right in the loop (InFront(target) && HasLineOfSight(objectTag)), and filter the objects out right in there, since only those objects are of interest.
Also, your HasLineOfSight() method checks the tag of the hit object, but what you probably wanted to do, is to check if the raycast actually hits that exact object. So it should instead compare the hit's gameObject to the target's gameObject, ignoring the tag, since a correct tag alone isn't enough. (Side note: it would make sense to place all "photographable objects" on a "photo layer", and set the layer mask in the Physics.Raycast() call accordingly, it's more efficient that way in larger scenes.)
The way the angles are calculated in the InFront() method is probably causing issues, because the direction vector to the target is really in 3D. To calculate the angles, you could try to use Vector3.Project() or Vector3.ProjectOnPlane(), but that will also be problematic, because of perspective camera issues.
This check is strongly related to the topic of "frustum culling", a technique usually used for rendering. But it's similar to what you need, to filter out all the (possibly) visible objects in the camera's field of view (frustum culling doesn't handle obstruction, it is just a geometric check to see if a point lies within the camera's frustum space). See:
https://en.wikipedia.org/wiki/Viewing_frustum
https://en.wikipedia.org/wiki/Hidden-surface_determination#Viewing-
http://www.lighthouse3d.com/tutorials/view-frustum-culling/
https://docs.unity3d.com/Manual/UnderstandingFrustum.html
If you want to dig deeper and optimize this, there are a couple of ways this can be done. But luckily, Unity comes with many useful related functions already built into the Camera class. So instead, you could use Camera.WorldToScreenPoint() (or Camera.WorldToViewportPoint()), and compare the resulting screen coordinates to the screen size or viewport, like discussed in Unity forum. (The frustum math is hidden behind these compact functions, but beware that this is probably not the optimal way to do this.)
Instead of calling FindGameObjectsWithTag() every time, you could do it only once in Start(), assuming objects do not get created/destroyed while the game is running.
I've tried to modify your script, since I'm also learning Unity again... The script can be dragged to the main camera, and it should show the "focus object" in the Scene view with the green debug line. I hope this helps:
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class PhotoCast : MonoBehaviour
{
public float maxDistance = 250.0f;
public string objectTag = "photo";
protected GameObject[] objs;
protected GameObject objFocus;
protected Camera cam;
public void Start() {
objs = GameObject.FindGameObjectsWithTag(objectTag);
cam = GetComponent<Camera>();
}
public void Update() {
if (Input.GetButtonDown("Fire1")) {
objFocus = CheckObjects();
if (objFocus) {
Debug.Log("closest object in view: " + objFocus.name);
/* TODO: take actual photo here */
}
}
if (objFocus) {
Debug.DrawLine(transform.position,
objFocus.transform.position, Color.green);
}
}
GameObject CheckObjects() {
GameObject obj_closest = null;
float dist_closest = float.MaxValue;
foreach (GameObject o in objs) {
float dist = Vector3.Distance(
o.transform.position, transform.position);
if (dist < maxDistance && dist < dist_closest
&& InViewport(o.transform.position)
&& HasLineOfSight(o.transform)) {
dist_closest = dist;
obj_closest = o;
}
}
return obj_closest;
}
bool InViewport(Vector3 worldPos) {
Vector3 p = cam.WorldToViewportPoint(worldPos);
return (p.x > 0.0f && p.x <= 1.0f && p.y > 0.0f && p.y <= 1.0f
&& p.z > cam.nearClipPlane);
}
bool HasLineOfSight(Transform target) {
RaycastHit hit;
Vector3 dir = target.position - transform.position;
if (Physics.Raycast(transform.position, dir, out hit, maxDistance)) {
if (hit.collider.gameObject == target.gameObject) {
return true;
}
}
return false;
}
}
Side notes:
Another issue with this technique is, that there can be tagged objects right in front of the camera, but other tagged objects that are closer on the side will be picked up instead of the obvious one. Many small issues to fine-tune until the scripts fits the game, I guess. Instead of only using one Raycast per object, you could use multiple ones, and take the bounding box or the actual collider shape into account.
An improved version of the script could make use of the Physics.Overlap*() or Physics.*Cast*() functions, documented here.
In previous version of d3fc my code was using fc.util.seriesPointSnapXOnly for snapping the crosshair.
This appears to be gone in the latest version of d3fc (or maybe I'm missing it in one of the standalone packages?).
I'm using the canvas implementation (annotationCanvasCrosshair) and it seems to also be missing the "snap" function where it was previously used like so:
fc.tool.crosshair()
.snap(fc.util.seriesPointSnapXOnly(line, series))
Additionally, "on" is also not available, so I can't attach events like trackingstart, trackingend, etc.
How can I implement a snapping crosshair now? The canvas version of the components are badly lacking examples. Does anyone have an example showing a snapping crosshair in the latest version of d3fc via canvas rendering?
Here's what I have so far https://codepen.io/parliament718/pen/xxbQGgp
I understand you've raised the issue with d3fc github, therefore I'll assume you are aware that util/snap.js is been deprecated.
Since this functionality unsupported now, it seems that the only feasible way to work around it will be to implement your own.
I took your pen and original snap.js code as starting point and applied the method outlined in Simple Crosshair example from the documentation.
I ended up having to add missing functions and their dependencies verbatim (surely you can refactor and package it up into a separate module):
function defined() {
var outerArguments = arguments;
return function(d, i) {
for (var c = 0, j = outerArguments.length; c < j; c++) {
if (outerArguments[c](d, i) == null) {
return false;
}
}
return true;
};
}
function minimum(data, accessor) {
return data.map(function(dataPoint, index) {
return [accessor(dataPoint, index), dataPoint, index];
}).reduce(function(accumulator, dataPoint) {
return accumulator[0] > dataPoint[0] ? dataPoint : accumulator;
}, [Number.MAX_VALUE, null, -1]);
}
function pointSnap(xScale, yScale, xValue, yValue, data, objectiveFunction) {
// a default function that computes the distance between two points
objectiveFunction = objectiveFunction || function(x, y, cx, cy) {
var dx = x - cx,
dy = y - cy;
return dx * dx + dy * dy;
};
return function(point) {
var filtered = data.filter(function(d, i) {
return defined(xValue, yValue)(d, i);
});
var nearest = minimum(filtered, function(d) {
return objectiveFunction(point.x, point.y, xScale(xValue(d)), yScale(yValue(d)));
})[1];
return [{
datum: nearest,
x: nearest ? xScale(xValue(nearest)) : point.x,
y: nearest ? yScale(yValue(nearest)) : point.y
}];
};
}
function seriesPointSnap(series, data, objectiveFunction) {
return function(point) {
var xScale = series.xScale(),
yScale = series.yScale(),
xValue = series.crossValue(),
yValue = (series.openValue).call(series);
return pointSnap(xScale, yScale, xValue, yValue, data, objectiveFunction)(point);
};
};
function seriesPointSnapXOnly(series, data) {
function objectiveFunction(x, y, cx, cy) {
var dx = x - cx;
return Math.abs(dx);
}
return seriesPointSnap(series, data, objectiveFunction);
}
The working end result can be seen here: https://codepen.io/timur_kh/pen/YzXXOOG. I basically defined two series and used a pointer component to update that second series data and trigger a re-render:
const data = {
series: stream.take(50), // your candle stick chart
crosshair: [] // second series to hold the crosshair position
};
.............
const crosshair = fc.annotationCanvasCrosshair() // define your crosshair
const multichart = fc.seriesCanvasMulti()
.series([candlesticks, crosshair]) // we've got two series now
.mapping((data, index, series) => {
switch(series[index]) {
case candlesticks:
return data.series;
case crosshair:
return data.crosshair;
}
});
.............
function render() {
d3.select('#zoom-chart')
.datum(data)
.call(chart);
// add the pointer component to the plot-area, re-rendering each time the event fires.
var pointer = fc.pointer()
.on('point', (event) => {
data.crosshair = seriesPointSnapXOnly(candlesticks, data.series)(event[0]);// and when we update the crosshair position - we snap it to the other series using the old library code.
render();
});
d3.select('#zoom-chart .plot-area')
.call(pointer);
}
UPD:
the functionality can be simplified like so, i also updated the pen:
function minimum(data, accessor) {
return data.map(function(dataPoint, index) {
return [accessor(dataPoint, index), dataPoint, index];
}).reduce(function(accumulator, dataPoint) {
return accumulator[0] > dataPoint[0] ? dataPoint : accumulator;
}, [Number.MAX_VALUE, null, -1]);
}
function seriesPointSnapXOnly(series, data, point) {
if (point == undefined) return []; // short circuit if data point was empty
var xScale = series.xScale(),
xValue = series.crossValue();
var filtered = data.filter((d) => (xValue(d) != null));
var nearest = minimum(filtered, (d) => Math.abs(point.x - xScale(xValue(d))))[1];
return [{
x: xScale(xValue(nearest)),
y: point.y
}];
};
This is far from polished, but I'm hoping it conveys the general idea.
I have 20 spites, I want them to be animated when a button is clicked.
Two types of animations 1) Position 2) Rotation.
Is there a recommended way to do this? Only way I can think of is recursively call setposition and angle with a delta value on Render method till the desired position and angle are reached.
When you have a start state and an end state, and you want to fill in the middle states, this is known as 'tweening (from inbetween). It comes from cartoon animation, but has come to be used more generally.
LibGDX makes use of Universal Tween Engine. You can start your journey to animating anything you want here. But, to give a bit more detail on how it works, here is an example from some of my own stuff. A similar usecase with regards to a sprite, but I have my sprites wrapped in a more generic class, a JJRenderNode. Here is how I make my class open to being tweened.
First you need a TweenAccessor for the class you want to tween.
public class RenderNodeTweenAccessor implements TweenAccessor<JJRenderNode> {
public static final int WIDTH = 1;
public static final int HEIGHT = 2;
public static final int WIDTH_HEIGHT = 3;
public static final int ALPHA = 4;
public static final int ALPHA_WIDTH_HEIGHT=5;
#Override
public int getValues(JJRenderNode target, int tweenType, float[] returnValues) {
switch (tweenType) {
case WIDTH:
returnValues[0] = target.getWidth();
return 1;
case HEIGHT:
returnValues[0] = target.getHeight();
return 1;
case WIDTH_HEIGHT:
returnValues[0] = target.getWidth();
returnValues[1] = target.getHeight();
return 2;
case ALPHA:
returnValues[0] = target.getColour().a;
return 1;
case ALPHA_WIDTH_HEIGHT:
returnValues[0] = target.getColour().a;
returnValues[1] = target.getWidth();
returnValues[2] = target.getHeight();
return 3;
default:
assert false;
return -1;
}
}
#Override
public void setValues(JJRenderNode target, int tweenType, float[] newValues) {
switch (tweenType) {
case WIDTH:
target.setWidth(newValues[0]);
break;
case HEIGHT:
target.setHeight(newValues[0]);
break;
case WIDTH_HEIGHT:
target.setWidth(newValues[0]);
target.setHeight(newValues[1]);
break;
case ALPHA:
target.getColour().a=newValues[0];
break;
case ALPHA_WIDTH_HEIGHT:
target.getColour().a=newValues[0];
target.setWidth(newValues[1]);
target.setHeight(newValues[2]);
default:
break;
}
}
}
The constant ints and the 'tweenType' in each of the get and set methods let you tween more than one combination of fields. In this case I have different combinations of width, height and alpha values for my JJRenderNode.
You have to register this TweenAccessor as follows:
Tween.registerAccessor(JJRenderNode.class, new RenderNodeTweenAccessor());
And then you are free to tween your class, for example:
Timeline.createSequence()
.push(Tween.set(node, RenderNodeTweenAccessor.WIDTH_HEIGHT).target(START_WIDTH, START_WIDTH))
.push(Tween.to(node, RenderNodeTweenAccessor.WIDTH_HEIGHT, 0.4f).target(PuzzleBlockCore.MAX_RENDER_WIDTH, PuzzleBlockCore.MAX_RENDER_WIDTH))
.start(JJ.tweenManager);
PS. You also need an instance of a TweenManger, and this needs to be updated with delta for each gameloop. I have a 'singleton' global instance that I use everywhere (JJ.TweenManager).
You might as well use spine 2d for animation. It costs, but it is worth it. For $60 I think, you get full libgdx support + bone rigging and animation.
http://esotericsoftware.com/
If you do want to animate with only libgdx however, you can create a list with all your sprite animations frames, loop through, and switch sprite texture to next frame in the animation.
private void render() {
sprite.set(aninationframes.get(currentFrame)
currentFrame = currentFrame + 1}
Though, you may want to add a delay per frame.
If(current time - time > some value) {
sprite.set(animationframes.get(currrntFrame)
currentFrame = currentFrame + 1
time = get current time here
}
Using Gluon Mobile 4 and Gluon Maps 1.0.1, I am displaying a map with a layer showing foot steps. When the users double clicks the mouse button, a new foot step is shown. This works great, but I currently need a workaround to convert from pointer coordinates (where the user clicked) to MapPoints (needed for the layer).
Here is how the mouse click is obtained:
public MainView(String name) {
super(name);
MapView mapView = new MapView();
mapView.setZoom(18f);
mapView.setCenter(NUREMBERG);
layer = new FootStepsLayer();
mapView.addLayer(layer);
setCenter(mapView);
layer.addPoint(NUREMBERG);
setOnMouseClicked(event -> {
if ((event.getButton() == MouseButton.PRIMARY)
&& (event.getClickCount() == 2)) {
double x = event.getX();
double y = event.getY();
layer.addPoint(x, y);
}
});
}
Currently my layer implementation looks like this:
public class FootStepsLayer extends MapLayer {
private static final Image FOOTSTEPS
= new Image(FootStepsLayer.class.getResourceAsStream("/footsteps.png"),
32, 32, true, true);
private final ObservableList<Pair<MapPoint, Node>> points
= FXCollections.observableArrayList();
public void addPoint(MapPoint mapPoint) {
Node node = new ImageView(FOOTSTEPS);
Pair<MapPoint, Node> pair = new Pair<>(mapPoint, node);
points.add(pair);
getChildren().add(node);
markDirty();
}
public void addPoint(double x, double y) {
Bounds bounds = baseMap.getParent().getLayoutBounds();
baseMap.moveX(x - bounds.getWidth() / 2);
baseMap.moveY(y - bounds.getHeight() / 2);
addPoint(new MapPoint(baseMap.centerLat().get(),
baseMap.centerLon().get()));
}
#Override
protected void layoutLayer() {
// Warning: suggested conversion to functional style crashed app on BlueStacks
for (Pair<MapPoint, Node> element : points) {
MapPoint mapPoint = element.getKey();
Node node = element.getValue();
Point2D point = baseMap.getMapPoint(mapPoint.getLatitude(), mapPoint.getLongitude());
node.setVisible(true);
node.setTranslateX(point.getX());
node.setTranslateY(point.getY());
}
}
}
My workaround is in public void addPoint(double x, double y): I am calling moveX() and moveY(), because after that I can query centerLat() and centerLong(). This is not ideal because the map moves and the new foot step becomes the center of the map. What I want is the map position to remain unchanged.
If I have not overlooked it, there seems to be no API for converting mouse coordinates to geo locations. As answered in question create a polyline in gluon mapLayer, the BaseMap class has two getMapPoint methods, but I have found none the other way round. But there must be a way to do it. ;-)
If you have a look at BaseMap, there is already one method that does precisely what you are looking for, but only for the center of the map: calculateCenterCoords.
Based on it, you could add your own method to BaseMap, where the sceneX and sceneY coordinates are taken into account instead:
public MapPoint getMapPosition(double sceneX, double sceneY) {
double x = sceneX - this.getTranslateX();
double y = sceneY - this.getTranslateY();
double z = zoom.get();
double latrad = Math.PI - (2 * Math.PI * y) / (Math.pow(2, z) * 256);
double mlat = Math.toDegrees(Math.atan(Math.sinh(latrad)));
double mlon = x / (256 * Math.pow(2, z)) * 360 - 180;
return new MapPoint(mlat, mlon);
}
Then you can expose this method in MapView:
public MapPoint getMapPosition(double sceneX, double sceneY) {
return baseMap.getMapPosition(sceneX, sceneY);
}
So you can use it on your map:
mapView.setOnMouseClicked(e -> {
MapPoint mapPosition = mapView.getMapPosition(e.getSceneX(), e.getSceneY());
System.out.println("mapPosition: " + mapPosition.getLatitude()+ ", " + mapPosition.getLongitude());
});
This method should be part of Maps, so feel free to create a feature request or even a pull request.