Извлечение координат из файла dxf autocad с помощью функции explode php

0
0

Функция explode() довольно проста, но чрезвычайно полезна и используется в кодировании постоянно. Если эта функция не применима, используют регулярные выражения, но они работают медленнее, поэтому выгодно работать с готовыми функциями php, чтобы ускорить свою программу.

Explode php: описание работы функции и ее практическое применение

Функция получает на вход строку, разбивает ее по делителю и присваивает значения массиву с числовыми ключами.

На примере файла dxf autocad давайте попробуем извлечь координаты и нарисовать чертеж с помощью GD Library php.

Файл dxf – это по сути обычный текстовый документ, в котором записаны координаты всех чертежей. Выглядит он так:

Файл dxf с чертежом многоугольника

ENTITIES – это сущности, LWPOLYLINE – замкнутый многоугольник, цифра 10 обозначает координату x, после нее идет значение (т. е., x=0.0), цифра 20 обозначает y, ее значение со следующей строки (т. е., y=500.0), ничего сложного.

Найдем в файле dxf необходимую нам информацию. Для этого применим функцию strchr(), которая найдет нам сущности (ENTITIES) и многоугольники (LWPOLYLINE):

$content = file_get_contents('stairs.dxf');
$entities = strchr($content, "ENTITIES");
$endsec = strchr($entities, "ENDSEC", true);
$entitie_string = $endsec;

Функция explode php поможет извлечь координаты. В этом примере используем только многоугольник, но в чертежах много и других фигур, поэтому присвоим их массиву. Мы рассматриваем только LWPOLYLINE:

$entities_array = array("LWPOLYLINE");

Следующий пример находит позиции всех LWPOLYLINE в текстовом документе dxf:

$lastPos = 0;
$positions_entities = array();
foreach($entities_array as $key_needle =>$entitie){
	while (($lastPos = strpos($entitie_string, $entitie, $lastPos))!== false) {
        $positions_entities[$lastPos] = $entitie;
        $lastPos = $lastPos + strlen($entitie);
	}
}
$array_keys_positions = array_keys($positions_entities);
$sizeof_array_positions = sizeof($array_keys_positions);
for($i=0; $i< $sizeof_array_positions; $i++){
    if(isset($array_keys_positions[$i+1])){
        $entities_string_array[$positions_entities[$array_keys_positions[$i]]][$array_keys_positions[$i]] = substr($entitie_string, $array_keys_positions[$i], $array_keys_positions[$i+1] - $array_keys_positions[$i] );
    }
    else{
        $entities_string_array[$positions_entities[$array_keys_positions[$i]]][$array_keys_positions[$i]] = substr($first_entitie_string, $array_keys_positions[$i] );
    }
}

Все строки многоугольников теперь находятся в массиве, т. е., у нас три многоугольника, а значит три ключа и три значения. В значениях находятся строки с информацией из файла dxf об этих многоугольниках. Теперь необходимо разбить эти строки, чтобы выделить из них координаты. Для этого используем explode():

foreach( $entities_string_array as $key_ent =>$value_ent){ 
	foreach( $value_ent as $key_val =>$value_e  ){
		$explode_value_e[$key_ent][$key_val] = explode(PHP_EOL,  $value_e);
	}
}

Из полученного многомерного массива получим значения, которые следуют за отметками 10 (x) и 20 (y):

$lwpolyline_array = $explode_value_e["LWPOLYLINE"];
$k = 0;
foreach( $lwpolyline_array as $lw_key => $explode_key ){
	foreach( $explode_key as $key => $lwpolyline_value){
		if( $lwpolyline_value == '10' ){
			$coordinates[$k][] = $coordinates_db[] = $coordinates_x[] = (float)$explode_key[$key+1];
		}else if( $lwpolyline_value == '20' ){
			$coordinates[$k][] = $coordinates_db[] = $coordinates_y[] = (float)$explode_key[$key+1];
		}
	}
	$implode_coordinates_db[$k] = implode(';',$coordinates_db);
	$k++;
}
$width = max($coordinates_x) - min($coordinates_x);
$height = max($coordinates_y) - min($coordinates_y);

Массив $coordinates содержит координаты многоугольников, $coordinates_db будем использовать для записи значений х и y в базу данных, а $coordinates_x и $coordinates_y нужны для определения ширины и высоты нашего рисунка в библиотеке GD php.

Объединение данных в строку с помощью implode() для компактного хранения информации в MySQL

Для хранения в базе данных соберем координаты в строку с помощью implode(), т. к. если хранить каждую точку в отдельной ячейке, то база данных постепенно разрастется до огромных размеров. Создавать таблицу в MySQL не будем, чтобы не усложнять код.

$implode_coordinates_db[$k] = implode(';',$coordinates_db);

Осталось написать функцию, которая будет рисовать картинку в GD Library:

$image_array = array($implode_coordinates_db, $width, $height);

Для создания картинки нам нужны координаты (будем использовать строку с координатами, которую можно извлечь из базы данных $implode_coordinates_db), ширина и высота.

Вызов функции:

$image_base64 = image_create($image_array);

И сама функция:

function image_create( $image_array ){
	$implode_coordinates = $image_array[0];
	$width = $image_array[1];
	$height = $image_array[2];
	$im = imagecreatetruecolor($width+1, $height+1);
	$white=imagecolorallocate($im,255,255,255);
	$black = imagecolorallocate($im, 0, 0, 0);
	imagefilledrectangle($im, 0, 0, $width, $height, $white);
	foreach( $implode_coordinates as $key =>$coordinates_string ){
		$coordinates[$key] = explode(';', $coordinates_string);
		$polygon_arrays_count[$key]=count($coordinates[$key])/2;
		imagepolygon($im, $coordinates[$key], $polygon_arrays_count[$key] , $black);
	}
	ob_start();
	imagepng($im);
	$buffer = ob_get_clean();
	//ob_end_clean();
	$img = base64_encode($buffer);
	imagedestroy($im);
	return $img;
}

Разбиение строки, полученной из MySQL с помощью explode()

Функция получает строчные координаты из базы данных, затем строка разбивается с помощью explode php, после чего imagepolygon() рисует нам многоугольники.

$coordinates[$key] = explode(';', $coordinates_string);
imagepolygon($im, $coordinates[$key], $polygon_arrays_count[$key] , $black);

Для данного примера картинка создана в формате imagepng base64_encode, но вы можете сохранить картинку в jpg или png.

Теперь можно вывести картинку в браузер:

$image_array = array($implode_coordinates_db, $width, $height);
$image_base64 = image_create($image_array);
$image_src='data:image/png;base64,'.$image_base64;
echo "<img src='".$image_src."'>";

Background картинки будет выглядеть так:

Background картинки image png base64_encode

Если есть возможность применить встроенные функции вместо регулярных выражений, то процесс выполнения программы будет занимать немного меньше времени, поэтому всегда имеет смысл сначала попытаться достичь поставленной цели с помощью готовых решений в php.

Весь код:

$content = file_get_contents('stairs.dxf');
$entities = strchr($content, "ENTITIES");
$endsec = strchr($entities, "ENDSEC", true);
$entitie_string = $endsec;

$entities_array = array("LWPOLYLINE");

$lastPos = 0;
$positions_entities = array();
foreach($entities_array as $key_needle =>$entitie){
	while (($lastPos = strpos($entitie_string, $entitie, $lastPos))!== false) {
        $positions_entities[$lastPos] = $entitie;
        $lastPos = $lastPos + strlen($entitie);
	}
}
$array_keys_positions = array_keys($positions_entities);
$sizeof_array_positions = sizeof($array_keys_positions);
for($i=0; $i< $sizeof_array_positions; $i++){
    if(isset($array_keys_positions[$i+1])){
        $entities_string_array[$positions_entities[$array_keys_positions[$i]]][$array_keys_positions[$i]] = substr($entitie_string, $array_keys_positions[$i], $array_keys_positions[$i+1] - $array_keys_positions[$i] );
    }
    else{
        $entities_string_array[$positions_entities[$array_keys_positions[$i]]][$array_keys_positions[$i]] = substr($entitie_string, $array_keys_positions[$i] );
    }
}
	
foreach( $entities_string_array as $key_ent =>$value_ent){ 
	foreach( $value_ent as $key_val =>$value_e  ){
		$explode_value_e[$key_ent][$key_val] = explode(PHP_EOL,  $value_e);
	}
}

$lwpolyline_array = $explode_value_e["LWPOLYLINE"];
$k = 0;
foreach( $lwpolyline_array as $lw_key => $explode_key ){
	foreach( $explode_key as $key => $lwpolyline_value){
		if( $lwpolyline_value == '10' ){
			$coordinates[$k][] = $coordinates_db[] = $coordinates_x[] = (float)$explode_key[$key+1];
		}else if( $lwpolyline_value == '20' ){
			$coordinates[$k][] = $coordinates_db[] = $coordinates_y[] = (float)$explode_key[$key+1];
		}
	}
	$implode_coordinates_db[$k] = implode(';',$coordinates_db);
	$k++;
}
$width = max($coordinates_x) - min($coordinates_x);
$height = max($coordinates_y) - min($coordinates_y);


function image_create( $image_array ){
	$implode_coordinates = $image_array[0];
	$width = $image_array[1];
	$height = $image_array[2];
	$im = imagecreatetruecolor($width+1, $height+1);
	$white=imagecolorallocate($im,255,255,255);
	$black = imagecolorallocate($im, 0, 0, 0);
	imagefilledrectangle($im, 0, 0, $width, $height, $white);
	foreach( $implode_coordinates as $key =>$coordinates_string ){
		$coordinates[$key] = explode(';', $coordinates_string);
		$polygon_arrays_count[$key]=count($coordinates[$key])/2;
		imagepolygon($im, $coordinates[$key], $polygon_arrays_count[$key] , $black);
	}
	ob_start();
	imagepng($im);
	$buffer = ob_get_clean();
	//ob_end_clean();
	$img = base64_encode($buffer);
	imagedestroy($im);
	return $img;
}

$image_array = array($implode_coordinates_db, $width, $height);
$image_base64 = image_create($image_array);
$image_src='data:image/png;base64,'.$image_base64;
echo "<img src='".$image_src."'>";