GeoTools DirectLayer Class Issues - layer

I'm working with DirectLayer to try and create a tool that I can use to draw boxes on a map that will be used to highlight features.
I'm looking for a way to make features that will resize and move with zoom and pan operations and not cause issues with other layers when they are created.
Right now the biggest issue is that when the DirectLayer draw function is called other layers in my map will render incorrectly or not render at all.
public class drawer extends DirectLayer{
private int x,y,w,h;
private Point center;
private boolean oval;
private Color main;
private Color shade;
private float diameter;
/**
* Empty constructor because there should be no persistent information to this class
* Defaults to a circle with diameter 20 and blue outline and shade
*/
public drawer()
{
diameter = 20;
shade = Color.BLUE;
main = Color.BLUE;
}
/**
* The actual drawing function, should not call this from the client, but has to be public to extend DirectLayer
*/
#Override
public void draw(Graphics2D graphics, MapContent map, MapViewport vp) {
graphics.setColor(main);
if(center == null)
{
if(!oval)
{
graphics.drawRect(x, y, w,h);
graphics.setColor(shade);
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float) .5));
graphics.fillRect(x, y, w,h);
}
else
{
graphics.drawOval(x, y, w, h);
graphics.setColor(shade);
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float) .5));
graphics.fillOval(x, y, w,h);
}
}
else
{
Shape theCircle = new Ellipse2D.Double(center.x - diameter/2, center.y - diameter/2, diameter, diameter);
graphics.draw(theCircle);
graphics.setColor(shade);
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float) .5));
graphics.fill(theCircle);
}
map.addLayer(this);
}
/**
* Draws a circle on the given map using the given graphics option
* #param graphics - graphics object from parentComponent
* #param center - center of circle (diameter is set using setDiameter)
* #param map - map to draw circle on
*/
public void drawCircle(Graphics2D graphics,Point center, MapContent map)
{
this.center = center;
draw(graphics,map,map.getViewport());
}
/**
* Draws a rectangle on the map with the given x and y coordinates and the given width and height on the Map
* #param graphics - graphics object from the parentcomponent
* #param x - Upper left x coordinate
* #param y - upper left y coordinate
* #param w - width
* #param h - height
* #param map - Map to draw on
*/
public void drawRectangle(Graphics2D graphics,int x, int y, int w, int h, MapContent map)
{
center = null;
oval = false;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
draw(graphics,map,map.getViewport());
}
/**
* Draws an oval on the map with the given x and y coordinates and the given width and height on the Map
* #param graphics - graphics object from the parentcomponent
* #param x - Upper left x coordinate
* #param y - upper left y coordinate
* #param w - width
* #param h - height
* #param map - Map to draw on
*/
public void drawOval(Graphics2D graphics,int x, int y, int w, int h, MapContent map)
{
oval = true;
center = null;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
draw(graphics,map,map.getViewport());
}
/**
* used to set outline color for shapes
* #param color - color to outline
*/
public void setGraphicsColor(Color color)
{
main = color;
}
/**
* Used to set color of shading
* #param color - color to shade
*/
public void setShaderColor(Color color)
{
shade = color;
}
/**
* Sets diameter of circles that are drawn using the drawCircle Method
* #param d - Diameter
*/
public void setDiameter(float d)
{
diameter = d;
}
/**
* removes all drawn shapes from the given map
* #param map - the map to remove shapes from
*/
public static void removeDrawings(MapContent map)
{
for(Layer l : map.layers())
{
if(l instanceof drawer)
{
l.preDispose();
map.removeLayer(l);
}
}
}
#Override
public ReferencedEnvelope getBounds() {
// TODO Auto-generated method stub
return null;
}
}
The issue here is that when I call DrawREctangle, when the rectangle is drawn on the screen other layers render incorrectly on the repaint. Also the rectangle does not zoom or pan with the screen as it has no featuresource.
I'm wondering what can I do about these two issues? Is DirectLayer actually what I am looking for or should I be trying to make a Drawable version of FeatureLayer, which just feels like the wrong way to go about this.

Related

my code is only drawing a straight line no matter how many sides i input in the pSides JTextFields

When I input a digit in the JTextfields it should pass through my actionListener to store all the values (ID, number of sides, length of sides and color) into an arraylist. It should then be used in my polygonContainer class that goes through a for loop and a polygon formula, then prints it out. However what comes out all the time is a straight line.
This is the code i tried:
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class ContainerFrame extends JFrame{
ArrayList<PolygonContainer> polygons = new ArrayList<>();
// JTextFields for the number of sides, side length, color, and ID
public JTextField pSides, pSidesLengths, pColor, pID;
// Button for submission
public JButton submitButton;
public void createComponents() {
// Initialize the JTextFields
pSides = new JTextField();
pSidesLengths = new JTextField();
pColor = new JTextField();
pID = new JTextField();
submitButton = new JButton("Submit");
submitButton.addActionListener(new ContainerButtonHandler(this));
JPanel textFieldsPanel = new JPanel();
// uses a gridlayout to organise the textfields then sets it as north
textFieldsPanel.setLayout(new GridLayout(5, 2));
textFieldsPanel.add(new JLabel("Sides:"));
textFieldsPanel.add(pSides);
textFieldsPanel.add(new JLabel("Sides Length:"));
textFieldsPanel.add(pSidesLengths);
textFieldsPanel.add(new JLabel("Color:"));
textFieldsPanel.add(pColor);
textFieldsPanel.add(new JLabel("ID:"));
textFieldsPanel.add(pID);
add(textFieldsPanel, BorderLayout.NORTH);
add(submitButton, BorderLayout.SOUTH);
JPanel drawPanel = new ContainerPanel(this);
add(drawPanel, BorderLayout.CENTER);
setSize(1600, 900);
setVisible(true);
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); // Close action.
}
public static void main(String[] args) {
ContainerFrame cFrame = new ContainerFrame();
cFrame.createComponents();
}
}
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
class ContainerButtonHandler implements ActionListener {
ContainerFrame theApp; // Reference to ContainerFrame object
// ButtonHandler constructor
ContainerButtonHandler(ContainerFrame app) {
theApp = app;
}
public void actionPerformed(ActionEvent e) {
// Get the text from the JTextFields using the getText method
String sides = theApp.pSides.getText();
String sidesLengths = theApp.pSidesLengths.getText();
String id = theApp.pID.getText();
//parse the values as integers
int intSides = Integer.parseInt(sides);
int intSidesLength = Integer.parseInt(sidesLengths);
int intId = Integer.parseInt(id);
//does the input validation where sides, sides length and id needs to be positive integers
if (intId >= 100000 && intId <= 999999 && intSides >= 0 && intSidesLength >= 0) {
// The inputs are valid
String color = theApp.pColor.getText();
// Store the values in an arraylist or other data structure
ArrayList<String> polygonArray = new ArrayList<String>();
polygonArray.add(sides);
polygonArray.add(sidesLengths);
polygonArray.add(color);
polygonArray.add(id);
PolygonContainer polygon = new PolygonContainer(polygonArray);
theApp.polygons.add(polygon);
theApp.repaint();
JOptionPane.showMessageDialog(theApp, "Polygon" + id + "was added to the list.", "Success", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(theApp, "The Polygon" + id + "was not added to the list as a valid Id was not provided.", "Error", JOptionPane.ERROR_MESSAGE);
}
}
}
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
public class PolygonContainer implements Comparable<PolygonContainer>{
Color pColor = Color.BLACK; // Colour of the polygon, set to a Colour object, default set to black
int pId = 000000; // Polygon ID should be a six digit non-negative integer
int pSides; // Number of sides of the polygon, should be non-negative value
int pSideLengths; // Length of each side in pixels of the polygon, should be non-negative value
int polyCenX; // x value of centre point (pixel) of polygon when drawn on the panel
int polyCenY; // y value of centre point (pixel of polygon when drawn on the panel
int [] pointsX; // int array containing x values of each vertex (corner point) of the polygon
int [] pointsY; // int array containing y values of each vertex (corner point) of the polygon
// Constructor currently set the number of sides and the equal length of each side of the Polygon
//Constructor that takes the values from the array
public PolygonContainer(ArrayList<String> values){
this.pSides = Integer.parseInt(values.get(0));
this.pSideLengths = Integer.parseInt(values.get(1));
this.pColor = Color.getColor(values.get(2));
this.pId = Integer.parseInt(values.get(3));
pointsX = new int[pSides];
pointsY = new int[pSides];
}
// Used to populate the points array with the vertices corners (points) and construct a polygon with the
// number of sides defined by pSides and the length of each side defined by pSideLength.
// Dimension object that is passed in as an argument is used to get the width and height of the ContainerPanel
// and used to determine the x and y values of its centre point that will be used to position the drawn Polygon.
public Polygon getPolygonPoints(Dimension dim) {
polyCenX = dim.width / 2; // x value of centre point of the polygon
polyCenY = dim.height / 2; // y value of centre point of the polygon
Polygon p = new Polygon();
for (int i = 0; i < pSides; i++) {
// Calculate the x and y coordinates of the ith point of the polygon
int x = polyCenX + pSideLengths * (int) Math.cos(2.0 * Math.PI * i / pSides);
int y = polyCenY + pSideLengths * (int) Math.sin(2.0 * Math.PI * i / pSides);
// Add the x and y coordinates to the pointsX and pointsY arrays
pointsX[i] = x;
pointsY[i] = y;
// Add the point to the polygon object using the addPoint method
p.addPoint(x, y);
}
return p;
}
// You will need to modify this method to set the colour of the Polygon to be drawn
// Remember that Graphics2D has a setColor() method available for this purpose
public void drawPolygon(Graphics2D g, Dimension d) {
//Set color of polygon
g.setColor(pColor);
Polygon p = getPolygonPoints(d);
g.draw(p);
//this creates a bounding box around the polygon
Rectangle2D bounds = p.getBounds2D();
g.draw(bounds);
}
// gets a stored ID
public int getID() {
return pId;
}
#Override
// method used for comparing PolygonContainer objects based on stored ids, you need to complete the method
public int compareTo(PolygonContainer o) {
return 0;
}
// outputs a string representation of the PolygonContainer object, you need to complete this to use for testing
public String toString()
{
return "";
}
}
import javax.swing.JPanel;
import java.awt.*;
public class ContainerPanel extends JPanel{
ContainerFrame conFrame;
public ContainerPanel(ContainerFrame cf) {
conFrame = cf; // reference to ContainerFrame object
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D comp = (Graphics2D)g; // You will need to use a Graphics2D objects for this
Dimension size = getSize(); // You will need to use this Dimension object to get
// the width / height of the JPanel in which the
// Polygon is going to be drawn
for (PolygonContainer polygon : conFrame.polygons) {
polygon.drawPolygon(comp, size);
}
}
}
JFrame

Camera and Game Character Rotation Issues (Unity - Third Person Character Controller)

I'm trying to edit the Third Person Controller script that's found in the 'Starter Assets' pack created by Unity (https://assetstore.unity.com/packages/essentials/starter-assets-third-person-character-controller-196526)
Note: Just a heads up that I am extremely new to coding, so please be as detailed with your answer as possible. Thanks in advance, I really appreciate it.
Current Situation (note: I'm building for mobile) -
My character moves forwards, diagonally forwards (top left, top right), and both left/right correctly and rotates to face that direction. The follow camera stays behind the character and rotates when the character does. This is all great.
The Problem - When my character moves backwards (pressing 'S' on the keyboard or 'Down on the Joystick' (mobile)) the character rotates causing the camera and character to rotate continuously on the spot. This is also the case when moving diagonally backwards (bottom left, bottom right).
What I Want To Achieve - I want it so that when backward input is detected, but only backwards, the character moves backward with no rotation to either the player or camera. Moving diagonally backwards however I would still like the rotation for the camera (not the player) but in the opposite direction.
Here is the part of the script that I believe controls this. If you could please assist me on how to edit, what to add/remove, that would be amazing.
// normalise input direction
Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
// note: Vector2's != operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// if there is a move input rotate player when the player is moving
if (_input.move != Vector2.zero)
{
_targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg +
_mainCamera.transform.eulerAngles.y;
float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, _targetRotation, ref _rotationVelocity,
RotationSmoothTime);
// rotate to face input direction relative to camera position
transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
Vector3 targetDirection = Quaternion.Euler(0.0f, _targetRotation, 0.0f) * Vector3.forward;
// move the player
_controller.Move(targetDirection.normalized * (_speed * Time.deltaTime) +
new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
Just in case the full script is required to assist me, please see it below;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
using UnityEngine.InputSystem;
#endif
/* Note: animations are called via the controller for both the character and capsule using animator null checks
*/
namespace StarterAssets
{
[RequireComponent(typeof(CharacterController))]
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
[RequireComponent(typeof(PlayerInput))]
#endif
public class ThirdPersonController : MonoBehaviour
{
[Header("Player")]
[Tooltip("Move speed of the character in m/s")]
public float MoveSpeed = 2.0f;
[Tooltip("Sprint speed of the character in m/s")]
public float SprintSpeed = 5.335f;
[Tooltip("How fast the character turns to face movement direction")]
[Range(0.0f, 0.3f)]
public float RotationSmoothTime = 0.12f;
[Tooltip("Acceleration and deceleration")]
public float SpeedChangeRate = 10.0f;
public AudioClip LandingAudioClip;
public AudioClip[] FootstepAudioClips;
[Range(0, 1)] public float FootstepAudioVolume = 0.5f;
[Space(10)]
[Tooltip("The height the player can jump")]
public float JumpHeight = 1.2f;
[Tooltip("The character uses its own gravity value. The engine default is -9.81f")]
public float Gravity = -15.0f;
[Space(10)]
[Tooltip("Time required to pass before being able to jump again. Set to 0f to instantly jump again")]
public float JumpTimeout = 0.50f;
[Tooltip("Time required to pass before entering the fall state. Useful for walking down stairs")]
public float FallTimeout = 0.15f;
[Header("Player Grounded")]
[Tooltip("If the character is grounded or not. Not part of the CharacterController built in grounded check")]
public bool Grounded = true;
[Tooltip("Useful for rough ground")]
public float GroundedOffset = -0.14f;
[Tooltip("The radius of the grounded check. Should match the radius of the CharacterController")]
public float GroundedRadius = 0.28f;
[Tooltip("What layers the character uses as ground")]
public LayerMask GroundLayers;
[Header("Cinemachine")]
[Tooltip("The follow target set in the Cinemachine Virtual Camera that the camera will follow")]
public GameObject CinemachineCameraTarget;
[Tooltip("How far in degrees can you move the camera up")]
public float TopClamp = 70.0f;
[Tooltip("How far in degrees can you move the camera down")]
public float BottomClamp = -30.0f;
[Tooltip("Additional degress to override the camera. Useful for fine tuning camera position when locked")]
public float CameraAngleOverride = 0.0f;
[Tooltip("For locking the camera position on all axis")]
public bool LockCameraPosition = false;
// cinemachine
private float _cinemachineTargetYaw;
private float _cinemachineTargetPitch;
// player
private float _speed;
private float _animationBlend;
private float _targetRotation = 0.0f;
private float _rotationVelocity;
private float _verticalVelocity;
private float _terminalVelocity = 53.0f;
// timeout deltatime
private float _jumpTimeoutDelta;
private float _fallTimeoutDelta;
// animation IDs
private int _animIDSpeed;
private int _animIDGrounded;
private int _animIDJump;
private int _animIDFreeFall;
private int _animIDMotionSpeed;
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
private PlayerInput _playerInput;
#endif
private Animator _animator;
private CharacterController _controller;
private StarterAssetsInputs _input;
private GameObject _mainCamera;
private const float _threshold = 0.01f;
private bool _hasAnimator;
private bool IsCurrentDeviceMouse
{
get
{
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
return _playerInput.currentControlScheme == "KeyboardMouse";
#else
return false;
#endif
}
}
private void Awake()
{
// get a reference to our main camera
if (_mainCamera == null)
{
_mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
}
}
private void Start()
{
_cinemachineTargetYaw = CinemachineCameraTarget.transform.rotation.eulerAngles.y;
_hasAnimator = TryGetComponent(out _animator);
_controller = GetComponent<CharacterController>();
_input = GetComponent<StarterAssetsInputs>();
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
_playerInput = GetComponent<PlayerInput>();
#else
Debug.LogError( "Starter Assets package is missing dependencies. Please use Tools/Starter Assets/Reinstall Dependencies to fix it");
#endif
AssignAnimationIDs();
// reset our timeouts on start
_jumpTimeoutDelta = JumpTimeout;
_fallTimeoutDelta = FallTimeout;
}
private void Update()
{
_hasAnimator = TryGetComponent(out _animator);
JumpAndGravity();
GroundedCheck();
Move();
}
private void LateUpdate()
{
CameraRotation();
}
private void AssignAnimationIDs()
{
_animIDSpeed = Animator.StringToHash("Speed");
_animIDGrounded = Animator.StringToHash("Grounded");
_animIDJump = Animator.StringToHash("Jump");
_animIDFreeFall = Animator.StringToHash("FreeFall");
_animIDMotionSpeed = Animator.StringToHash("MotionSpeed");
}
private void GroundedCheck()
{
// set sphere position, with offset
Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset,
transform.position.z);
Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers,
QueryTriggerInteraction.Ignore);
// update animator if using character
if (_hasAnimator)
{
_animator.SetBool(_animIDGrounded, Grounded);
}
}
private void CameraRotation()
{
// if there is an input and camera position is not fixed
if (_input.look.sqrMagnitude >= _threshold && !LockCameraPosition)
{
//Don't multiply mouse input by Time.deltaTime;
float deltaTimeMultiplier = IsCurrentDeviceMouse ? 0.1f : Time.deltaTime;
_cinemachineTargetYaw += _input.look.x * deltaTimeMultiplier;
_cinemachineTargetPitch += _input.look.y * deltaTimeMultiplier;
}
// clamp our rotations so our values are limited 360 degrees
_cinemachineTargetYaw = ClampAngle(_cinemachineTargetYaw, float.MinValue, float.MaxValue);
_cinemachineTargetPitch = ClampAngle(_cinemachineTargetPitch, BottomClamp, TopClamp);
// Cinemachine will follow this target
CinemachineCameraTarget.transform.rotation = Quaternion.Euler(_cinemachineTargetPitch + CameraAngleOverride,
_cinemachineTargetYaw, 0.0f);
}
private void Move()
{
// set target speed based on move speed, sprint speed and if sprint is pressed
float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
// a simplistic acceleration and deceleration designed to be easy to remove, replace, or iterate upon
// note: Vector2's == operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// if there is no input, set the target speed to 0
if (_input.move == Vector2.zero) targetSpeed = 0.0f;
// a reference to the players current horizontal velocity
float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
float speedOffset = 0.1f;
float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 0.0f;
// accelerate or decelerate to target speed
if (currentHorizontalSpeed < targetSpeed - speedOffset ||
currentHorizontalSpeed > targetSpeed + speedOffset)
{
// creates curved result rather than a linear one giving a more organic speed change
// note T in Lerp is clamped, so we don't need to clamp our speed
_speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude,
Time.deltaTime * SpeedChangeRate);
// round speed to 3 decimal places
_speed = Mathf.Round(_speed * 1000f) / 1000f;
}
else
{
_speed = targetSpeed;
}
_animationBlend = Mathf.Lerp(_animationBlend, targetSpeed, Time.deltaTime * SpeedChangeRate);
if (_animationBlend < 0.01f) _animationBlend = 0f;
// normalise input direction
Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
// note: Vector2's != operator uses approximation so is not floating point error prone, and is cheaper than magnitude
// if there is a move input rotate player when the player is moving
if (_input.move != Vector2.zero)
{
_targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg +
_mainCamera.transform.eulerAngles.y;
float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, _targetRotation, ref _rotationVelocity,
RotationSmoothTime);
// rotate to face input direction relative to camera position
transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
Vector3 targetDirection = Quaternion.Euler(0.0f, _targetRotation, 0.0f) * Vector3.forward;
// move the player
_controller.Move(targetDirection.normalized * (_speed * Time.deltaTime) +
new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
// update animator if using character
if (_hasAnimator)
{
_animator.SetFloat(_animIDSpeed, _animationBlend);
_animator.SetFloat(_animIDMotionSpeed, inputMagnitude);
}
}
private void JumpAndGravity()
{
if (Grounded)
{
// reset the fall timeout timer
_fallTimeoutDelta = FallTimeout;
// update animator if using character
if (_hasAnimator)
{
_animator.SetBool(_animIDJump, false);
_animator.SetBool(_animIDFreeFall, false);
}
// stop our velocity dropping infinitely when grounded
if (_verticalVelocity < 0.0f)
{
_verticalVelocity = -2f;
}
// Jump
if (_input.jump && _jumpTimeoutDelta <= 0.0f)
{
// the square root of H * -2 * G = how much velocity needed to reach desired height
_verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity);
// update animator if using character
if (_hasAnimator)
{
_animator.SetBool(_animIDJump, true);
}
}
// jump timeout
if (_jumpTimeoutDelta >= 0.0f)
{
_jumpTimeoutDelta -= Time.deltaTime;
}
}
else
{
// reset the jump timeout timer
_jumpTimeoutDelta = JumpTimeout;
// fall timeout
if (_fallTimeoutDelta >= 0.0f)
{
_fallTimeoutDelta -= Time.deltaTime;
}
else
{
// update animator if using character
if (_hasAnimator)
{
_animator.SetBool(_animIDFreeFall, true);
}
}
// if we are not grounded, do not jump
_input.jump = false;
}
// apply gravity over time if under terminal (multiply by delta time twice to linearly speed up over time)
if (_verticalVelocity < _terminalVelocity)
{
_verticalVelocity += Gravity * Time.deltaTime;
}
}
private static float ClampAngle(float lfAngle, float lfMin, float lfMax)
{
if (lfAngle < -360f) lfAngle += 360f;
if (lfAngle > 360f) lfAngle -= 360f;
return Mathf.Clamp(lfAngle, lfMin, lfMax);
}
private void OnDrawGizmosSelected()
{
Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f);
Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f);
if (Grounded) Gizmos.color = transparentGreen;
else Gizmos.color = transparentRed;
// when selected, draw a gizmo in the position of, and matching radius of, the grounded collider
Gizmos.DrawSphere(
new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z),
GroundedRadius);
}
private void OnFootstep(AnimationEvent animationEvent)
{
if (animationEvent.animatorClipInfo.weight > 0.5f)
{
if (FootstepAudioClips.Length > 0)
{
var index = Random.Range(0, FootstepAudioClips.Length);
AudioSource.PlayClipAtPoint(FootstepAudioClips[index], transform.TransformPoint(_controller.center), FootstepAudioVolume);
}
}
}
private void OnLand(AnimationEvent animationEvent)
{
if (animationEvent.animatorClipInfo.weight > 0.5f)
{
AudioSource.PlayClipAtPoint(LandingAudioClip, transform.TransformPoint(_controller.center), FootstepAudioVolume);
}
}
}
}

MPAndroidChart MarkerView in fixed position

Is there any way to have fixed position for MarkerView? I need to have it fixed in top left or top right corner.
This is one approach to fix the marker on the Top Left or Top Right
Once you've created the custom MarkerView here's what you can do.
1) You can set an id to the parent view/layout and using that id you can get it's width.
layoutWidth = customLayout.getWidth();
2) You can then override draw and do the following:
#Override
public void draw(Canvas canvas, float posX, float posY) {
if (posX > (canvas.getWidth() / 2.0))
//Check if the user is in the right half of the canvas
super.draw(canvas, leftXPos, leftYPos);
//Draw marker on the left top corner
else
//Otherwise draw the marker on the top right corner.
super.draw(canvas, canvas.getWidth() - layoutWidth, rightYPos);
}
You can set the values for leftXPos, leftYPos and rightYPos to whatever looks and feels best.
Hope this helps!
You should create a custom MarkerView, like in the documentation.
Then, customize getXOffset and getYOffset like this:
#Override
public int getXOffset(float xpos) {
// this will cause the marker-view to be at left of the screen
return -(int)xpos;
}
#Override
public int getYOffset(float ypos) {
// this will cause the marker-view to be at top screen
return -(int)ypos;
getXOffset(float xpos) and getYOffset(float ypos) are not overridden by the MarkerView class anymore. To fix the Marker position, You have to override the getOffsetForDrawingAtPoint(float posX, float posY) method in the following way:
private MPPointF mOffset;
#Override
public MPPointF getOffsetForDrawingAtPoint(float posX, float posY) {
if(mOffset == null) {
// center the marker horizontally and fixed Y position at the top
mOffset = new MPPointF(-(getWidth() / 2f), -posY);
}
return mOffset;
}
MpandroidChart v3.1.0 :
class MarkerView constructor(
context: Context,
) :
MarkerView(context, R.layout.marker_view) {
private val totalWidth = resources.displayMetrics.widthPixels
override fun refreshContent(e: Entry?, highlight: Highlight?) {
//...
super.refreshContent(e, highlight)
}
override fun getOffsetForDrawingAtPoint(posX: Float, posY: Float): MPPointF {
val supposedX = posX + width
val mpPointF = MPPointF()
mpPointF.x = when {
supposedX > totalWidth -> -width.toFloat()
posX - width < 0 -> 0f
else -> 0f
}
mpPointF.y = if (posY > height)
-height.toFloat()
else
0f
return mpPointF
}
}
in this implementation the default location for MarkerView is to the top-right of the point, if there is enough space, else may be to top-left , bottom-left or bottom-right of it .you can change this behaviour based on your needs.
notice that this only Workes if chart's width is set to MATCH_PARENT.

Stage.addListener not working in libgdx

I am just trying to add a click listener to the stage in libgdx but it is not working here is my code;
stage.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log("CLICK", "LISTENER");
parallaxBackground.reverse();
return super.touchDown(event, x, y, pointer, button);
}
});
This is from my main game screen, which inherits from an abstract screen which calls,
Gdx.input.setInputProcessor(stage);
In the abstract class I also call,
stage.act(delta);
I am most definetely calling super.render() as well from the child class
What is causing this!
EDIT
I don't know if it matters but my stage has no actors but I just want to simply acknowledge a click.
Since you added no actors to your stage, your stage has no substance so it cannot be touched.
You can add create an actor that is the same size as the screen and is aligned with the screen to do what you're trying. Something like this (untested):
Actor screenActor = new Actor(){
public void act (float delta) {
super.act(delta);
Viewport viewport = getStage().getViewport();
width = viewport.getScreenWidth();
height = viewport.getScreenHeight();
x = viewport.getScreenX();
y = viewport.getScreenY();
}
};
stage.addActor(screenActor);
You would add this actor first, so other actors get first crack at intercepting touches, and this is the fallback.
Here is how I solved this problem:
In Photoshop I created a 100x100px image and put only one layer in it and set the opacity of that layer to 1%, I also removed the background (This made a totally transparent image) and saved it as .png to use it as texture.
I created an Actor and called it BgActor and drew the texture to it.
Here is the png image that I created
and here is how my Actor looks like:
The BgActor class:
public class BgActor extends Actor {
private float x, y, width, height;
private Texture texture = new Texture(Gdx.files.internal("images/transparent-bg.png"));
public BgActor(float x, float y, float width, float height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
setTouchable(Touchable.enabled);
}
#Override
public void draw(Batch batch, float parentAlpha) {
setBounds(x, y, width, height);
batch.draw(texture, x, y, width, height);
}
public void dispose() {
texture.dispose();
}
}
Implementation (I used your Listener):
BgActor bgActor = new BgActor(0, 0, stage.getWidth(), stage.getHeight);
bgActor.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log("CLICK", "LISTENER");
parallaxBackground.reverse();
return super.touchDown(event, x, y, pointer, button);
}
});
......
stage.addActor(bgActor);
And don't forget to dispose the bgActor in your Screen's hide() method.
Good luck ..

How to find the Joint coordinates(X,Y,Z) ,also how to draw a locus of the tracked joint?

I am trying to develop a logic to recognize a circle which is made by users right hand, I got the code to draw the skeleton and track from the sample code,
private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
Skeleton[] skeletons = new Skeleton[0];
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null)
{
skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
skeletonFrame.CopySkeletonDataTo(skeletons);
}
}
using (DrawingContext dc = this.drawingGroup.Open())
{
// Draw a transparent background to set the render size
dc.DrawRectangle(Brushes.Black, null, new Rect(0.0, 0.0, RenderWidth, RenderHeight));
if (skeletons.Length != 0)
{
foreach (Skeleton skel in skeletons)
{
RenderClippedEdges(skel, dc);
if (skel.TrackingState == SkeletonTrackingState.Tracked)
{
this.DrawBonesAndJoints(skel, dc);
}
else if (skel.TrackingState == SkeletonTrackingState.PositionOnly)
{
dc.DrawEllipse(
this.centerPointBrush,
null,
this.SkeletonPointToScreen(skel.Position),
BodyCenterThickness,
BodyCenterThickness);
}
}
}
// prevent drawing outside of our render area
this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight));
}
}
What I want to do now is to track the coordinates of users right hand for gesture recognition,
Here is how I am planning to get the job done:
Start the gesture
Draw the circled gesture, Make sure to store the coordinates for start and then keep noting the coordinates for every 45 degree shift of the Joint from the start, for 8 octants we will get 8 samples.
For making a decision that a circle was drawn we can just check the relation ship between the eight samples.
Also, in the depthimage I want to show the locus of the drawn gesture, so as the handpoint moves it leaves a trace behind so at the end we will get a figure which was drawn by an user. I have no idea how to achieve this.
Coordinates for each joint are available for each tracked skeleton during each SkeletonFrameReady event. Inside your foreach loop...
foreach (Skeleton skeleton in skeletons) {
// get the joint
Joint rightHand = skeleton.Joints[JointType.HandRight];
// get the individual points of the right hand
double rightX = rightHand.Position.X;
double rightY = rightHand.Position.Y;
double rightZ = rightHand.Position.Z;
}
You can look at the JointType enum to pull out any of the joints and work with the individual coordinates.
To draw your gesture trail you can use the DrawContext you have in your example or use another way to draw a Path onto the visual layer. With your x/y/z values, you would need to scale them to the window coordinates. The "Coding4Fun" library offers a pre-built function to do it; alternatively you can write your own, for example:
private static double ScaleY(Joint joint)
{
double y = ((SystemParameters.PrimaryScreenHeight / 0.4) * -joint.Position.Y) + (SystemParameters.PrimaryScreenHeight / 2);
return y;
}
private static void ScaleXY(Joint shoulderCenter, bool rightHand, Joint joint, out int scaledX, out int scaledY)
{
double screenWidth = SystemParameters.PrimaryScreenWidth;
double x = 0;
double y = ScaleY(joint);
// if rightHand then place shouldCenter on left of screen
// else place shouldCenter on right of screen
if (rightHand)
{
x = (joint.Position.X - shoulderCenter.Position.X) * screenWidth * 2;
}
else
{
x = screenWidth - ((shoulderCenter.Position.X - joint.Position.X) * (screenWidth * 2));
}
if (x < 0)
{
x = 0;
}
else if (x > screenWidth - 5)
{
x = screenWidth - 5;
}
if (y < 0)
{
y = 0;
}
scaledX = (int)x;
scaledY = (int)y;
}