Merge connected UIBezierPaths - objective-c

Is there some way (code or pseudo-code algorithm) to utilize UIBezierPath instance methods like appendPath to "merge" any number of connected, distinct UIBezierPaths into a single big path? In a document with many paths, I am trying to reduce the encoded file size by perhaps reducing the number of paths as there is surely some redundant information there. If I am barking up the wrong tree, let me know.

In my case, I had few logically connected paths that together form a closed shape and I wanted to fill this closed shape. This cannot be done if you just append(_:) them together as the fill would simply applied to each path. I looked at similar questions asked but none of them solved the problem. So I wrote this extension to merge logically connected paths together to form a single path.
If you have path1, path2 and path3 logically form a closed shape. Call them in the same order
let mergedPath = UIBezierPath()
mergedPath.merge(with: path1)
mergedPath.merge(with: path2)
mergedPath.merge(with: path3)
import UIKit
extension UIBezierPath {
func merge(with path: UIBezierPath) {
let currentPath = self.cgPath.mutableCopy()!
let lastPoint = self.lastPoint()
let firstPoint = path.firstPoint()
var index = -1
path.cgPath.applyWithBlock { block in
index += 1
let element = block.pointee
switch (element.type) {
case .moveToPoint:
if index != 0 && lastPoint != firstPoint || lastPoint == nil {
currentPath.move(to: element.points[0])
}
case .addLineToPoint:
currentPath.addLine(to: element.points[0])
case .addQuadCurveToPoint:
currentPath.addQuadCurve(to: element.points[1], control: element.points[0])
case .addCurveToPoint:
currentPath.addCurve(to: element.points[2], control1: element.points[0], control2: element.points[1])
case .closeSubpath:
currentPath.closeSubpath()
#unknown default:
fatalError()
}
}
self.cgPath = currentPath
}
func firstPoint() -> CGPoint? {
var firstPoint: CGPoint? = nil
var index = -1
self.cgPath.applyWithBlock { block in
index += 1
let element = block.pointee
if index == 0 {
if element.type == .moveToPoint || element.type == .addLineToPoint {
firstPoint = element.points[0]
} else if element.type == .addQuadCurveToPoint {
firstPoint = element.points[1]
} else if element.type == .addCurveToPoint {
firstPoint = element.points[2]
}
}
}
return firstPoint
}
func lastPoint() -> CGPoint? {
var lastPoint: CGPoint? = nil
var index = -1
self.reversing().cgPath.applyWithBlock { block in
index += 1
let element = block.pointee
if index == 0 {
if element.type == .moveToPoint || element.type == .addLineToPoint {
lastPoint = element.points[0]
} else if element.type == .addQuadCurveToPoint {
lastPoint = element.points[1]
} else if element.type == .addCurveToPoint {
lastPoint = element.points[2]
}
}
}
return lastPoint
}
}

well if its only an esthetically problem...just set the first point of the 2nd bezier curve as the last point of the 1st..and so on..
if its not i don't think there is a way to merge 2 or more bezier paths cuz ...well..they are bezier and it wont look right if you do
read more about bezier curves
bezier curves and see why it wont work

Related

How can I make a sprite unable to pass through lines?

So I've imported a maze image (png) as the background of my canvas, and drawn lines over the corresponding lines in the image in p5. I've created a sprite which is my 'character' and it's just a small image, and all it's doing at the moment is moving with the arrow keys on top of the maze image. I want this to move through this maze and not go through any of these lines. I'm sure its a really simple answer but I can't wrap my head around it. Here is my code:
var spr;
var slimeMould;
var maze;
var line1;
var line2;
var line3;
var line4;
var line5;
var line6;
var line7;
var line8;
var line9;
var line10;
var line11;
var line12;
var line13;
var line14;
var line15;
var line16;
var line17;
function preload () {
slimeMould = loadImage("assets/slimemould-01.png");
maze = loadImage("assets/maze-02.png");
}
function setup() {
createCanvas(1000, 1000);
imageMode(CENTER)
spr = createSprite(595, 100);
spr.addImage(slimeMould);
}
function draw() {
background(10);
fill(255);
noStroke();
image(maze,width/2,height/2);
textAlign(CENTER, CENTER);
textSize(25);
text("find the shortest route to the food!", width/2, height*0.79);
drawSprites();
strokeWeight(15);
stroke(255);
line1 = line(86,168,460,168);
line2 = line(460,168,460,265);
line3 = line(460,265,310,265);
line4 = line(310,265,310,220);
line5 = line(310,220,380,220);
line6 = line(86,168,86,730);
line7 = line(140,168,140,220);
line8 = line(240,220,240,410);
line9 = line(140,260,240,260);
line10 = line(140,260,140,360);
line11 = line(140,360,190,360);
line12 = line(190,360,190,330);
line13 = line(86,410,140,410);
line14 = line(140,410,140,508);
line15 = line(86,553,125,553);
line16 = line(125,553,125,619);
line17 = line(125,619,260,619);
}
function keyPressed() {
if (keyCode == RIGHT_ARROW) {
spr.setSpeed(1.75, 0);
}
else if (keyCode == DOWN_ARROW) {
spr.setSpeed(1.75, 90);
}
else if (keyCode == LEFT_ARROW) {
spr.setSpeed(1.75, 180);
}
else if (keyCode == UP_ARROW) {
spr.setSpeed(1.75, 270);
}
return false;
}
function keyReleased() {
if (keyCode == RIGHT_ARROW) {
spr.setSpeed(0,0);
}
else if (keyCode == DOWN_ARROW) {
spr.setSpeed(0,0);
}
else if (keyCode == LEFT_ARROW) {
spr.setSpeed(0,0);
}
else if (keyCode == UP_ARROW) {
spr.setSpeed(0,0);
}
return false;
}
You're looking for collision detection. Specifically it sounds like you want line-rectangle collision detection. Googling "line rectangle collision detection" will return a ton of results, including:
How to check if line segment intersects a rectangle?
Line intersection with AABB Rectangle?
How to know if a line intersects a rectangle
How to test if a line segment intersects an axis-aligned rectange in 2D?
But basically, it sounds like the general approach is to break your rectangle down into 4 lines and then do line-line intersection detection. Another option would be to treat the lines in your maze as rectangles and then do rectangle-rectangle collision detection.

How do you get DIRECTION of PDF is L2R or R2L

I want want to programmatically read a PDF file to find out if it is read either L2R or R2L.
How can I determine this programmatically?
I use ASP.NET C#.
我找到讀取方法了,若有更好的方法請再回覆,方法如下:
I find reading method, and if a better way please reply again, as follows:
//讀取左翻或右翻
//reading DIRECTION is a L2R or R2L
booFlipLeft = true;
if (objReader.Catalog != null) {
if (((PdfDictionary)objReader.Catalog).Contains(PdfName.VIEWERPREFERENCES) == true) {
if (((PdfDictionary)((PdfDictionary)objReader.Catalog).Get(PdfName.VIEWERPREFERENCES)).Contains(PdfName.DIRECTION) == true) {
if (((PdfName)((PdfDictionary)((PdfDictionary)objReader.Catalog).Get(PdfName.VIEWERPREFERENCES)).Get(PdfName.DIRECTION)).Equals(PdfName.R2L) == true) {
booFlipLeft = false;
}
}
}
}
TextBox1.Text += "翻頁:" + (booFlipLeft == true ? "左翻" : "右翻") ;
TextBox1.Text += "Flip:" + (booFlipLeft == true ? "Left" : "Right");

removing last node linked list in objective -c

I am trying to implement a removeLast function for a linked list in objective-c. My add function property works well because I can see the node I created, but when I try to remove a node it does not work. I have tried looking up general solutions for this, but have not come up with anything. Is there something special with objective-c that I should take a look at?
-(void) removeLast{
Node *newNode = [[Node alloc]init];
Node *tail = [[Node alloc]init];
if (self.head == NULL){
NSLog(#"No items to remove");
}
else{
newNode = self.head;
tail= self.head;
while (tail != NULL) {
tail = tail.next;
if (tail != NULL){
newNode = tail;
}
}
newNode.next = NULL;
}
}
I believe you've overcomplicated the algorithm. You don't need to keep a reference to the previous link if you always look one step ahead:
- (void) removeLast {
if (self.head == NULL) {
NSLog(#"Empty list");
} else if (self.head.next == NULL) {
self.head = NULL;
} else {
Node* current = self.head;
while (current.next.next != NULL)
current = current.next;
current.next = NULL;
}
}
This iterates through until it reaches the next-to-last node when current.next.next will be null. Then it makes that the last node.

Finding BST's height non-recursively?

This is a recursive method for finding the height, but i have a very large number of nodes in my binary search tree, and i want to find the height of the tree as well as assign the height to each individual sub-tree. So the recursive method throws stackoverflow exception, how do i do this non-recursively and without using stack?
private int FindHeight(TreeNode node)
{
if (node == null)
{
return -1;
}
else
{
node.Height = 1 + Math.Max(FindHeight(node.Left), FindHeight(node.Right));
return node.Height;
}
}
I believe i have to use post order traversal but without stack?
I was able to make this method, and it does return the correct height but it assigns each node with its depth not height.
public void FindHeight()
{
int maxHeight = 0;
Queue<TreeNode> Q = new Queue<TreeNode>();
TreeNode node;
Q.Enqueue(Root);
while (Q.Count != 0)
{
node = Q.Dequeue();
int nodeHeight = node.Height;
if (node.Left != null)
{
node.Left.Height = nodeHeight + 1;
Q.Enqueue(node.Left);
}
if (node.Right != null)
{
node.Right.Height = nodeHeight + 1;
Q.Enqueue(node.Right);
}
if (nodeHeight > maxHeight)
{
maxHeight = nodeHeight;
}
}
Console.WriteLine(maxHeight);
}

How to code the chess stalemate rule ?

I'm trying to write a chess game and find that I cannot find solutions to find a stalemate situation. I'm trying to google, but can't find anything. Is there a well-known algorithm or something?
Your move generator will be one of two different designs;
either it checks for legality while generating the moves
or you generate all possible moves and remove those that are illegal afterwards.
The former is better as it doesn't need post-processing.
A stalemate condition is simply one where there are no legal moves and the moving-side's king is not in check. A checkmate condition is one where there are no legal moves but the moving-side's king is in check.
In other words if you've figured out how to detect check and checkmate, you've already got everything necessary to detect stalemate.
Here is an Open-source code with all the rules for the classic Chess game:
https://github.com/cjortegon/basic-chess
You can run the project right after cloning the project (Android, iOS, Desktop and Web), or you can use the main logic, which is here: https://github.com/cjortegon/basic-chess/tree/master/libgdx/core/src/com/mountainreacher/chess/model
I based my solution on a 3-moments algorithm, first moment is when the player selects a piece from the board, then when the destination of this piece has been chosen and finally when the piece reaches that position (considering that it is an animated game, if not, you can merge step 2 and 3).
The following code has been implemented in Java. From the properties of the model class:
boolean turn;
GenericPiece selected, conquest;
ClassicBoard board;
List<int[]> possibleMovements;
int checkType;
The first method will handle moments 1, 2 and the special 'conquest' moment (applied to pawn piece only):
public boolean onCellClick(int row, int column) {
if (row == -1 && conquest != null) {
checkType = 0;
conquest.changeFigure(column);
return true;
} else if (selected != null) {
if (possibleMovements != null) {
for (int[] move : possibleMovements) {
if (move[0] == row && move[1] == column) {
// Move the PieceActor to the desired position
if (selected.moveTo(row, column)) {
turn = !turn;
}
break;
}
}
}
selected = null;
possibleMovements = null;
return true;
} else {
selected = board.getSelected(turn ? Piece.WHITE_TEAM : Piece.BLACK_TEAM, row, column);
if (selected != null) {
possibleMovements = new ArrayList<>();
possibleMovements.addAll(((GenericPiece) selected).getMoves(board, false));
// Checking the movements
board.checkPossibleMovements(selected, possibleMovements);
if (possibleMovements.size() == 0) {
possibleMovements = null;
selected = null;
return false;
} else {
return true;
}
}
}
return false;
}
And the following method will handle the 3rd moment (when animation finishes):
public void movedPiece(Piece piece) {
Gdx.app.log(TAG, "movedPiece(" + piece.getType() + ")");
// Killing the enemy
Piece killed = board.getSelectedNotInTeam(piece.getTeam(),
piece.getRow(), piece.getColumn());
if (killed != null) {
killed.setAvailable(false);
}
// Checking hacks
GenericPiece[] threat = board.kingIsInDanger();
if (threat != null) {
checkType = board.hasAvailableMoves(threat[0].getTeam()) ? CHECK : CHECK_MATE;
} else {
checkType = NO_CHECK;
}
// Checking castling
if (piece.getFigure() == Piece.ROOK && ((GenericPiece) piece).getMovesCount() == 1) {
Piece king = board.getSelected(piece.getTeam(),
piece.getRow(), piece.getColumn() + 1);
if (king != null && king.getFigure() == Piece.KING && ((GenericPiece) king).getMovesCount() == 0) {
// Left Rook
if (board.getSelected(piece.getRow(), piece.getColumn() - 1) == null) {
king.moveTo(piece.getRow(), piece.getColumn() - 1);
}
} else {
king = board.getSelected(piece.getTeam(),
piece.getRow(), piece.getColumn() - 1);
if (king != null && king.getFigure() == Piece.KING && ((GenericPiece) king).getMovesCount() == 0) {
// Right Rook
if (board.getSelected(piece.getRow(), piece.getColumn() + 1) == null) {
king.moveTo(piece.getRow(), piece.getColumn() + 1);
}
}
}
}
// Conquest
else if (piece.getFigure() == Piece.PAWN && (piece.getRow() == 0 || piece.getRow() == board.getRows() - 1)) {
conquest = (GenericPiece) piece;
checkType = CONQUEST;
}
}
That code covers all the rules from the classic chess, including: regular piece movements, castling, check, check-mate and conquests of pawns.