ページ 11

2つの座標データ(.txt)を比較する方法を教えてください。

Posted: 2017年9月19日(火) 23:12
by eee_eriko
C言語初心者です。初めてこの掲示板を利用させていただきます。

別のプログラムで書いた座標データを比較して、
一致する点だけを抽出するプログラムを教えていただきたいです。

入力ファイルの拡張子は.txtになっています。
出力ファイルの拡張子も.txtを考えています。

ググってもぴんとくるものがなかったので質問させていただきます。

Re: 2つの座標データ(.txt)を比較する方法を教えてください。

Posted: 2017年9月20日(水) 00:33
by スヌーピー
まず、

1.どういったフォーマットで.txtのファイルに座標が記録されているのか?
2.「一致する点」の定義は何か?

を明確にして頂かないと、望んだ回答が得られないかもしれませんよ。



>1.どういったフォーマットで.txtのファイルに座標が記録されているのか?

2次元のユークリッド空間の座標系を考えています。

ファイルには、ASCIIコードにて、

x座標[,カンマ]y座標[改行コード]
x座標[,カンマ]y座標[改行コード]
x座標[,カンマ]y座標[改行コード]
・・・

の様なフォーマットで記述されております。


>2.「一致する点」の定義は何か?

比較対象の点同士のx座標とy座標の値が共に等しい場合、「一致する点」と判定されるものとします。


等は明示した方が宜しいかと思います。

Re: 2つの座標データ(.txt)を比較する方法を教えてください。

Posted: 2017年9月20日(水) 01:09
by eee_eriko
返信ありがとうございます。
そうですよね、情報不足ですみませんでした。

>1.どういったフォーマットで.txtのファイルに座標が記録されているのか?

もともと3DCGによって作られたモデルから座標を取り出した、3次元の座標系です。
以下のようなデータになっています。

[tab=30]VIEW POINT
[tab=30]4000.00 1000.00 2000.00
[tab=30]Max dist
[tab=30]2500
[tab=30]ver_no
[tab=30]360
[tab=30]VISIBLE AREA POINT
[tab=30]6500.000000 1000.000000 -500.000000
[tab=30]6499.620000 1043.630000 -500.000000
[tab=30]6498.480000 1087.250000 -500.000000
[tab=30]・・・

VISIBLE AREA POINT以下は
x座標 y座標 z座標
・・・
になっています。


>2.「一致する点」の定義は何か?

上記のデータの内のx座標、y座標、z座標の値が等しい場合
「一致する点」と定義します。


以上の条件を追加でお願いします。

Re: 2つの座標データ(.txt)を比較する方法を教えてください。

Posted: 2017年9月20日(水) 03:23
by スヌーピー
以下は一例だと思って読んで下さい。

・"in1.txt"
・"in2.txt"

の座標データを比較し、

・"out.txt"

に出力する処理です。

処理としては非効率的ですので、座標が増えると大変かもしれません。(その場合、ソートされた座標を処理する等の工夫も有効かと思います。)

また、このプログラムの場合、微妙なフォーマットの違いでも、違う座標として弾かれるリスクが高まる為、注意が必要と思われます。(例えば、一方の座標にはスペースが2個連続しており、一方はスペースが1個という場合、同じ座標値でも弾かれる場合もある事でしょう。)

今回は、丸投げの引き受けではなく、サンプルコードの提示という認識ですので、簡単なコードに留めておきますが、実際に実装する際には、もう少し工夫が必要と言えますので、その点はご留意頂きたく思います。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

//ファイルサイズの取得
long get_data_size(char *path){
	FILE *fp;
	int i;
	
	if((fp=fopen(path,"r")) == NULL) return 0;
	for(i=1;(fgetc(fp)) != EOF;i++);
	fclose(fp);
	
	return i;
}

//ファイルの読み込み
char* load_data(char *path){
	char *data,c;
	int i;
	FILE *fp;
	
	data=(char*)malloc(sizeof(char)*get_data_size(path));
	if(data == NULL) return NULL;
	if((fp=fopen(path,"r")) == NULL) return NULL;
	for(i=0;(c=fgetc(fp)) != EOF;i++) data[i]=c;
	data[i]='\0';
	fclose(fp);
	
	return data;
}

//出力ファイルの初期化
int init_file(void){
	FILE *wfp;
	int i;
	
	wfp=fopen("out.txt","w+");
	for(i=0;""[i] != '\0';i++) fputc(""[i],wfp);
	fclose(wfp);
	
	return 0;
}

//出力ファイルに追記
int add_data(char *str){
	FILE *wfp;
	int i;
	
	wfp=fopen("out.txt","a+");
	for(i=0;str[i] != '\0';i++) fputc(str[i],wfp);
	fclose(wfp);
	
	return 0;
}

int main(void){
	char *in1,*in2;
	char key_word[1024];
	
	int in1_adr,i;
	
	//メモリにファイルのデータをロード(点の数が多くなった場合、ファイルを直に読むと遅くなる可能性があるため。)
	in1=load_data("in1.txt");
	if(in1==NULL) return 1;
	
	in2=load_data("in2.txt");
	if(in2==NULL){
		free(in1);
		return 1;
	}
	
	//'A'は座標データの直近の行にしか無いので、そこまで、カウンタを進め、
	for(in1_adr=0;in1[in1_adr] != 'A';in1_adr++);
	
	//ここで、改行コードまで読み進める(次のデータから、座標データの始まり)
	for(;in1[in1_adr] != '\n' && in1[in1_adr] != '\0';in1_adr++);
	
	//出力ファイルの初期化
	init_file();
	
	for(;1;){
		//座標データの最初の1文字まで、添え字を進める
		for(;isdigit(in1[in1_adr]) == 0 && in1[in1_adr] != '\0';in1_adr++);
		if(in1[in1_adr] == '\0') break;
		
		//座標データ1つを抜き出す
		for(i=0;isdigit(in1[in1_adr]) == 1 || in1[in1_adr] == '.' || in1[in1_adr] == ' ' || in1[in1_adr] == '-' || in1[in1_adr] == '+';in1_adr++,i++) key_word[i]=in1[in1_adr];
		key_word[i]='\0';
		
		//in1の座標がin2に存在した場合、
		if(strstr(in2,key_word) != NULL){
			//その座標の文字列を、出力用ファイルに追記する。
			add_data(key_word);
			add_data("\n");
		}
	}
	
	return 0;
}


Re: 2つの座標データ(.txt)を比較する方法を教えてください。

Posted: 2017年9月20日(水) 03:36
by スヌーピー
今読んで気付きましたが、

コード:

//座標データの最初の1文字まで、添え字を進める
for(;isdigit(in1[in1_adr]) == 0 && in1[in1_adr] != '\0';in1_adr++);
この部分は、x座標が負の値だった場合や、"0.1"を".1"の様に表現する場合等にバグになる気がしました。

失礼いたしました。

他にもバグがあるのかもしれませんので、参考程度に見てください。

Re: 2つの座標データ(.txt)を比較する方法を教えてください。

Posted: 2017年9月20日(水) 05:57
by かずま
スヌーピー さんが書きました:

コード:

		//座標データ1つを抜き出す
		for(i=0;isdigit(in1[in1_adr]) == 1 || in1[in1_adr] == '.' || in1[in1_adr] == ' ' || in1[in1_adr] == '-' || in1[in1_adr] == '+';in1_adr++,i++) key_word[i]=in1[in1_adr];
g++ でコンパイルすると、isdigit('0') が 1 になるんですが、
gcc や VC++ だと 1 になりません。

私もサンプルプログラムを書いてみました。
データのサイズを固定値にしているので、その辺は修正が必要でしょう。

コード:

#include <stdio.h>   // fopen, fclose, fgets, fscanf, fprintf
#include <string.h>  // strstr
 
#define N 3000

double a[N][3];

int main(void)
{
    int i, n = 0;
    double d[3];
    char buf[1024];
    FILE *fin, *fout;
    fin = fopen("in1.txt", "r");
    if (!fin) return 1;
    while (fgets(buf, sizeof buf, fin) && !strstr(buf, "VISIBLE")) ;
    while (n < N && fscanf(fin, "%lf%lf%lf", &a[n][0], &a[n][1], &a[n][2]) == 3) n++;
    fclose(fin);

    fin = fopen("in2.txt", "r");
    if (!fin) return 2;
    fout = fopen("out.txt", "w");
    if (!fout) return 3;
    while (fgets(buf, sizeof buf, fin) && !strstr(buf, "VISIBLE")) ;
    while (fscanf(fin, "%lf%lf%lf", &d[0], &d[1], &d[2]) == 3) {
        for (i = 0; i < n && (d[0]!=a[i][0] || d[1]!=a[i][1] || d[2]!=a[i][2]); i++) ;
        if (i < n) fprintf(fout, "%f %f %f\n", d[0], d[1], d[2]);
    }
    fclose(fin);
    fclose(fout);

    return 0;
}
参考になりますか?

Re: 2つの座標データ(.txt)を比較する方法を教えてください。

Posted: 2017年9月20日(水) 15:02
by eee_eriko
スヌーピー 様

これを参考に知人にも手伝ってもらい修正して実行したら
理想に近いデータが取り出せました。
ただ、実際に扱うデータの座標は多くなってくるのでもう少し検討してみます。
ありがとうございました!


かずま様

サンプルプログラムの提案ありがとうございます。
流れが結構シンプルで大量のデータも扱えるようにできそうです。
参考にさせてもらいます。
ありがとうございます!